How to use select statement in SQL Server on conditions - c#

I want to filter data on conditions using combo boxes in c#, so I used this stored procedure:
CREATE PROCEDURE [dbo].[GET_FIXING_ON_CONDITIONS]
#BranchID int,
#MachGroupID int,
#FailGroupID int,
#FailID int,
#MachNo varchar(50),
#DateFrom date,
#DateTO date
AS
SELECT tbBranches.BranchName,
tbMachines.MachNo,
tbMachines.MachType,
tbMachinesGroups.MachGroupName,
tbFails.FailName,
tbFailsGroups.FailGroupName,
tbFailsType.FailTypeName,
tbFixing.FixDate,
tbFixing.FixDetails,
tbFixing.FixPerson
FROM tbMachines
INNER JOIN tbFixing ON tbMachines.MachNo = tbFixing.FixMachNo
AND tbMachines.BranchID = tbFixing.BranchID
INNER JOIN tbFailsGroups ON tbMachines.BranchID = tbFailsGroups.BranchID
INNER JOIN tbFailsType ON tbMachines.BranchID = tbFailsType.BranchID
INNER JOIN tbFails ON tbFixing.FixFailID = tbFails.FailID
AND tbFixing.BranchID = tbFails.BranchID
AND tbFailsGroups.FailGroupID = tbFails.FailGroupID
AND tbFailsGroups.BranchID = tbFails.BranchID
AND tbFailsType.FailTypeID = tbFails.FailType
AND tbFailsType.BranchID = tbFails.BranchID
INNER JOIN tbMachinesGroups ON tbMachines.MachGroupID = tbMachinesGroups.MachGroupID
AND tbMachines.BranchID = tbMachinesGroups.BranchID
INNER JOIN tbBranches ON tbMachines.BranchID = tbBranches.BranchID
AND tbFixing.BranchID = tbBranches.BranchID
WHERE tbBranches.BranchID = #BranchID
AND tbMachinesGroups.MachGroupID = #MachGroupID
AND tbFailsGroups.FailGroupID = #FailGroupID
AND tbFails.FailID = #FailID
AND tbMachines.MachNo = #MachNo
AND tbFixing.FixDate >= #DateFrom
AND tbFixing.FixDate <= #DateTO;
Parameters are compensated by the 7 combo boxes but the problem is I have to choose (all) parameters values to display the data and this is not required,
what I want is display data once I choose (any) value from any combo box

Most generally, you would do this by passing null to any parameter which has not been set by the user and the query follows this pattern:
WHERE (#BranchID IS NULL OR tbBranches.BranchID = #BranchID)
AND (MachGroupID IS NULL OR tbMachinesGroups.MachGroupID = #MachGroupID)
AND ...

It depends what you pass in your parameters if they are not specified in your C# app. (I personally pass NULLs in such a case).
I used to use a query structure like this:
SELECT ...
WHERE
(#Param1 IS NULL OR [Value1] = #Param1) AND
(#Param2 IS NULL OR [Value2] = #Param2) AND
...

Related

How do I change SQL Left Join to Lambda expression in C#?

I have three tables and one input value. As a first step, based on the #Input, I need to fetch DSType from DSTypes table. Now again I need to compare DSType of DSTypes with RTInput table's IType column value. If RTInput table has matching records then need to fetch the ID column value alone otherwise NULL should be assigned.
I achieved this logic in SQL but unable to achieve the same in Lambda expression.
I tried some code from google but that is not returning correct value.
DECLARE #ID
#ID = SELECT ID FROM DSMaster Where DSTId = #Input
SELECT RTI.ID FROM DSTypes(NOLOCK) DST
LEFT JOIN RTInput(NOLOCK) RTI
ON RTRIM(LTRIM(DST.DSType)) = RTRIM(LTRIM(RTI.IType))
WHERE DST.ID = #ID
Lambda expression which I tried:
using (BEContext beContext = new BEContext())
{
var mData = beContext.DSMaster.Where(r => r.DSTId = inputvalue);
var Id = beContext.RTInput.Join(beContext.DSTypes.Where(dst => dst.ID == mData.Id )).Select(z => z.ID).FirstOrDefault();
}
I think this may help.
using {BEContext beContext = new BEContext()){
var mData = (from p in beContext.DSMaster.Where(r=>r.DSTId == inputvalue)
join pr in beContext.RTInput on p.Id equals dst.ID
select new {
//select what you want
}).FirstOrDefault();

How to add column in SELECT statement dynamically in tSQL based on condition?

I am creating a tSql with parameters and based on some condition I want to add column in SELECT statement and I am not sure how to do it.
My Logic:
var keywordClause = keyword.IsNotEmpty()
? "[Name] like '%" + keyword + "%'"
: "1 = 1";
// keywordClause = "[Name] like '%Test%'"
var orderBy = sortParameters.ToOrderBy();
// orderBy = "Name ASC"
var parameters = new List<SqlParameter>
{
new SqlParameter("#Keyword", keywordClause),
new SqlParameter("#OrderBy", orderBy)
};
var sql = string.Format(#"SELECT Id,
Name,
CreateDateTime Created
FROM CallCenter WITH (NOLOCK)
WHERE(IsDeleted = 0)
AND #Keyword
ORDER BY #OrderBy");
return _PageList(ctx => ctx.CallCenterSummaries.SqlQuery(sql, parameters.ToArray())
.AsQueryable()
.Select(d => d.TrimSpaces()), page, pageSize);
Based on my logic, I am expecting this query:
SELECT Id,
Name,
CreateDateTime Created
FROM CallCenter WITH (NOLOCK)
WHERE(IsDeleted = 0)
AND [Name] like '%Test%'
ORDER BY Name ASC;
Here I am getting "An expression of non-boolean type specified in a context where a condition is expected, near 'ORDER'." exception and I believe it is taking Name as a string. How can I get desired results?
You can't have SqlParameter as an entire clause - it needs to be right hand side of the clause. For your scenario - the below should work.
var parameters = new List<SqlParameter>
{
new SqlParameter("#Keyword", keyword.IsNotEmpty() ? keyword : "%")
};
var sql = string.Format($#"SELECT Id,
Name,
CreateDateTime Created
FROM CallCenter WITH (NOLOCK)
WHERE(IsDeleted = 0)
AND [Name] like #Keyword
ORDER BY {orderBy}");
EDIT:
I've edited my code sample to use order by as a value in the interpolated string rather than as a SqlParameter, however, this does open you up to a Sql injection if the value of the orderBy is influenced by user's inputs.
Alternatively, I would recommend not using ORDER BY clause at all in your query and sorting results in memory before passing them back for display.

how to select values from 3 tables + count()

I have three Tables :
tbl_Publisher [Publisher_ID, addr,account-num,...,city];
tbl_Title [Title_ID, frequency, publisher,.., Publisher_ID];
tbl_Invoice [Invoice_ID, ordered_Date,...,Title_ID];
I would like to return a list of Titles by Publisher and each Title has the count number of Invoices it contains. in one result set.
I'm using a stored procedure as following :
PROCEDURE [dbo].[usp_GetTitlesbyPublisher]
-- Add the parameters for the stored procedure here
#PublisherID INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
-- Insert statements for procedure here
SELECT Title_ID,TitleName,pub_type,Frequency , Holdings ,tbl_Title.publisher ,section ,tbl_Title.Publisher_ID from tbl_Title, tbl_Publisher
where tbl_Title.Publisher_ID = tbl_Publisher.Publisher_ID
and #PublisherID = tbl_Publisher.Publisher_ID
END
How can I return the number of Invoice by each Title ?
You can probably accomplish this with a GROUP BY:
SELECT t.Title_ID, t.TitleName, p.pub_type,
t.Frequency, Holdings, t.publisher, section,
t.Publisher_ID, count(i.Invoice_ID) as NoOfInvoices
from tbl_Title t
inner join tbl_Publisher p on t.Publisher_ID = p.Publisher_ID
left join tbl_Invoice i on i.Title_ID = t.Title_ID
where #PublisherID = p.Publisher_ID
group by t.Title_ID, t.TitleName, p.pub_type, t.Frequency,
Holdings, t.publisher, section, t.Publisher_ID
Not checked the syntax on this.
SELECT COUNT(tbl_Invoice.Invoice_ID) 'InvoiceCount',Title_ID,TitleName,pub_type,Frequency, Holdings ,tbl_Title.publisher ,section ,tbl_Title.Publisher_ID
FROM tbl_Title
INNER JOIN tbl_Publisher ON tbl_Publisher.Publisher_ID = tbl_Title.Publisher_ID
INNER JOIN tbl_Invoice ON tbl_Invoice.Invoice_ID = tbl_Title.Invoice_ID
WHERE tbl_Publisher.Publisher_ID = #PublisherID
GROUP BY
Title_ID,TitleName,pub_type,Frequency, Holdings ,tbl_Title.publisher ,section ,tbl_Title.Publisher_ID

SQL IN Clause with string paramater list not listing all records

I'm passing a string variable to an IN Clause in sql (Stored Procedure). When declaring and setting the variable in sql I get back all the data that is required. But when setting the variable from c# I'm only receiving data based on the first status within that paramater.
I've got a function to split the statuses in the paramater list to retrieve the records:
ALTER FUNCTION [dbo].[fnSplit](
#sInputList VARCHAR(8000)
, #sDelimiter VARCHAR(10) = ';'
) RETURNS #List TABLE (item VARCHAR(8000))
BEGIN
DECLARE #sItem VARCHAR(8000)
WHILE CHARINDEX(#sDelimiter,#sInputList,0) <> 0
BEGIN
SELECT
#sItem=RTRIM(LTRIM(SUBSTRING(#sInputList,1,CHARINDEX(#sDelimiter,#sInputList,0)-1))),
#sInputList=RTRIM(LTRIM(SUBSTRING(#sInputList,CHARINDEX(#sDelimiter,#sInputList,0)+LEN(#sDelimiter),LEN(#sInputList))))
IF LEN(#sItem) > 0
INSERT INTO #List SELECT #sItem
END
IF LEN(#sInputList) > 0
INSERT INTO #List SELECT #sInputList
RETURN
END
My stored procedure is built like this:
ALTER procedure [dbo].[Get_RequestsAtEachStage]
(#managerRef int,
#status varchar(20))
as
BEGIN
WITH MaxStatusDate
as
(
select rs.requestID,rs.status from (
SELECT requestID,MAX([DateCreated]) AS MaxDate
FROM [LoanRequest].[dbo].[requestStatus]
GROUP BY RequestID) maxg
inner join [LoanRequest].[dbo].[requestStatus] rs on maxg.requestid = rs.requestid and maxg.MaxDate = rs.DateCreated
)
SELECT lr.ID, lr.serialNo, lr.model, lr.clientName, lr.address, lr.telephone, lr.contactName,
lr.swop, lr.substitueOfGoods, lr.printFunction, lr.copyFunction, lr.scanFunction,
lr.faxFunction, lr.controller, lr.controllerEmailAddress,
ml.Name, wl.Location, rt.requestType AS RequestTypeName, rs.status
FROM [dbo].[loanRequest] lr
INNER JOIN [dbo].[managersList] ml ON lr.managerRef = ml.ID
INNER JOIN [dbo].[warehouseList] wl ON lr.warehouseID = wl.ID
INNER JOIN [dbo].[requestType] rt ON lr.requestType = rt.ID
INNER JOIN MaxStatusDate rs ON lr.ID = rs.requestID
WHERE (#managerRef is null or lr.managerRef = #managerRef) AND rs.status IN (SELECT item FROM [dbo].[fnSplit](#status, ';'))
END
Based on the page the user access it will send through the appropriate statusses and retrieve the necessary records.
Setting the paramaters in sql as follows works perfect, I retrieve all the records:
DECLARE #managerRef INT
DECLARE #status NVARCHAR(100)
SET #managerRef = NULL
SET #status = 'Allocated;Readings Updated'
But, when I send it through c# within a string, it only retrieves records with the status of Allocated.:
string status = "Allocated;Readings Updated";
DataTable dtDevices = d.PopulateDevicesApproval(managerRef, status);
My method to retrieve the data from sql:
string filterstring = "";
filterstring = "Get_RequestsAtEachStage ";
cn = new SqlConnection(GetConnectionString());
SqlCommand myCmd = new SqlCommand(filterstring, cn);
myCmd.CommandType = CommandType.StoredProcedure;
cn.Open();
myCmd.Parameters.AddWithValue("#managerRef", managerRef);
myCmd.Parameters.AddWithValue("#status", status);
DataTable dt = new DataTable();
dt.Load(myCmd.ExecuteReader());
return dt;
Is there anything I am doing wrong?
--------- EDIT -----------
Running SELECT item FROM [dbo].fnSplit results from both c# and sql
Returning results from c#:
And returning results from sql:

SQL Server SELECT statement filter by passed in string array

I have a table called MyProducts and I want to return item1 and item2
SELECT item1, item2 from MyProducts
However I want it to be filtered on a string array I pass in (from C#). This is a very big table, so I an 'IN' statement is out. How would I do this using a join statement. Thanks!
There's no reason that IN statement is "out"; ultimately, that is a perfectly reasonable way of filtering - let the optimizer worry about the various options. It certainly isn't impacted by the fact that MyProducts is large. Adding a join makes more work: it does not, however, reduce the number of "hits", or the work involved. For example, to do that with dapper is just:
string[] filter = ...
var rows = connection.Query(
"select item1, item2 from MyProducts where SomeField in #filter",
new {filter});
or with LINQ:
string[] filter = ...
var rows = db.Products.Where(x => filter.Contains(x.SomeField));
One solution is to create a temporary table and join with it. The temporary table can have an index on the column on which you will be joining.
I always liked this method...
CREATE FUNCTION dbo.Split(#String varchar(max), #Delimiter char(1))
returns #temptable TABLE (Value varchar(max))
as
begin
declare #idx int
declare #slice varchar(max)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
then you can do this...
CREATE PROCEDURE MySp
#list varchar(max)
AS
SELECT <columns>
FROM <mytable> mt
INNER JOIN dbo.split(#list,',') s ON s.Value= my.Key
NOTE: There are many Split functions out there so you do not have to use this specific one.
Another method I have used when using SQL Server 2008 is using a table parameter like this...
CREATE TYPE [dbo].[LookupTable] As Table
(
ID Int primary key
)
CREATE PROCEDURE [dbo].[SampleProcedure]
(
#idTable As [dbo].[LookupTable] Readonly
)
AS
BEGIN
SELECT <columns>
FROM <mytable> mt
INNER JOIN #idTable s ON s.Id= my.Key
END
Pass the parameter into SQL Server from C# in this manner...
DataTable dataTable = new DataTable("SampleDataType");
dataTable.Columns.Add("Id", typeof(Int32));
foreach (var id in <mycollectionofids>)
dataTable.Rows.Add(id);
SqlParameter parameter = new SqlParameter();
parameter.ParameterName="#Id";
parameter.SqlDbType = System.Data.SqlDbType.Structured;
parameter.Value = dataTable;
command.Parameters.Add(parameter);

Categories