Search with multiple parameters in SQL Server - c#

This question is related to both c# and SQL Server.
I want to figure out how to do a custom search.
I have three tables
Customer
CusId, Name, Telephone
Employee
EmpId, Name, Job
Appointment
AppId, Date, EmpId, CusId
My C# form has three checkboxes. I want to find the data according to those checked values.
Ex: when customer,employee,app check boxes have selected, I want to find data on depending on all those three values.
When only two or one is selected I want to search depending on those selection. Here there will be total 6 combinations.
How to write a query to get correct result when I pass those values as parameters to a stored procedure.
Do I have to write 6 stored procedures to get the result?
Are there any methods to do this easily?
Please help me to fix this matter. Thanks in advance.

With a query such as the below (would suggest in a stored proc):
-- Parameters to a SQL sproc
DECLARE #CustID INT, #EmpID INT, #AppointmentID INT
-- Set Parameters here for testing
SELECT *
FROM Appointment as A
INNER JOIN Employee as E
ON E.EmpID = A.EmpId
INNER JOIN Customer as C
ON C.CusID = A.CusID
WHERE (#CustID IS NULL OR C.CUsID = #CustID)
AND (#EmpID IS NULL OR E.EmpID = #EmpID)
AND (#AppointmentID IS NULL OR A.AppID = #AppointmentID)
You then need to pass in the parameters appropriately, either an ID if selected, or null if not filtering on one item.

Related

Checking multiple columns have any of multiple values in a Table value parameter

I am trying to create a query to help get a list of accounts from an existing database. I will have two lists of integers passed in through two Table Value Parameters(TVP) from C#. I then need to see if multiple columns have any of the values in the corresponding TVP tables. The TVP lists of integers are provided by different clients and may differ between clients. That is why they are TVP's to allow the values to be passed in as parameters.
The data structure cannot be changed, it is created based on data from another system. Comments about changing the data structure won't be helpful. To help I will talk about an example table that would help show what I need.
Looking at a table like the following:
Table Accounts
varchar(200) AccountId
int StatusId1
int StatusId2
int StatusId3
int StatusId4
int Identifier1
int Identifier2
int Identifier3
int Identifier4
int Identifier5
I know that I can do a sql statement like:
Select AccountId from Accounts where StatusId1 In (1,2,3)
I was able to learn that I can reverse the In command as well:
Select AccountId from Accounts where 1 In (StatusId1, StatusId2, StatusId3, StatusId4)
This only lets me check one value against each column. The problem is I need to mix the two while using the TVP for the list of integers.
The closest I have been able to create is the following:
--Load the TVP lists
SELECT * INTO #StatusCodes FROM #StatusId
SELECT * INTO #IdentityCodes FROM #IdentifierId
--Find the Accounts that have the chosen Ids
SELECT AccountId
FROM Accounts
WHERE StatusId1 IN( SELECT Id FROM #StatusCodes)
OR StatusId2 IN( SELECT Id FROM #StatusCodes)
OR StatusId3 IN( SELECT Id FROM #StatusCodes)
OR StatusId4 IN( SELECT Id FROM #StatusCodes)
OR Identifier1 IN (SELECT Id FROM #IdentityCodes)
OR Identifier2 IN (SELECT Id FROM #IdentityCodes)
OR Identifier3 IN (SELECT Id FROM #IdentityCodes)
OR Identifier4 IN (SELECT Id FROM #IdentityCodes)
OR Identifier5 IN (SELECT Id FROM #IdentityCodes)
This query worked in my prototype and I got back the list of accounts that had at least one of these ids. I see a lot of select statements and it doesn't look very good. I am not sure how well it performs either. I am wondering if there is a better way to do this?
This is for a system that creates a report based on conditions our clients make. Each client runs from a couple to 100 reports each night. That means this is run possibly hundreds of times each night. While it isn't a system running thousands of times per hour, it does process a lot of data. Some of the databases it will search will be big with lots of accounts to search.
One option uses exists:
select a.acountId
from accounts a
where
exists (
select 1
from #StatusCodes s
where s.id in (a.StatusId1, a.StatusId2, a.StatusId3, a.StatusId4)
)
or exists (
select 1
from #IdentityCodes i
where i.id in (a.Identifier1, a.Identifier2, a.Identifier3, a.Identifier4)
)

Is there a limit of the output of a JOIN statement

In reporting Services, the user can choose a list with different customers. The report then generates total figures for the chosen customers. I have 2 tables in the report that incorporate the total revenue. However, when you choose all customers, the totals of the 2 tables differs. For every individual customer however, the tables match.
In the first table I use a simple query like this:
select revenue from customers where customernumber in (#CustomerNumber)
This one always shows the correct figures. However, for the second table, I have to call a stored procedure:
create procedure calculaterevenue (
#customernumber varchar(1200), #customercategory varchar(255)=NULL
)
In the procedure, a table valued function is used to take all the customernumbers that are in a comma-separated list and make then usable for the in operator:
and customernumber in (select value from fnStringToList',',#customernumber)
In the Dataset of the report, I have added an parameter #Customers that is
=JOIN(Parameters!Customernumber.Value,",")
And I call my procedure with
exec calculaterevenue (#Customers)
This works perfectly, until you select a lot of customers. I suspect the problem lies within the JOIN. Is there a maximum output for the JOIN statement?

select rows not contained in table

I have a table containing an ID as follows:
ID
----------------
10000V9F
10000V9O
10000VAh
10000VCB
10000VDn
10000VE9
10000VF4
10000VFE
10000VFH
10000VFW
10000VG9
Now I want to get all the data from another table that has none of these IDs. Therefor I create a query similar to this one:
SELECT * from TABLE1 where ID NOT IN (...)
Where ... is a list of IDs a got via another query and that contains all the previously mentioned IDs from the first table. This list is defined as follows:
string idString = "'" + String.Join("'", this.GetIDsForTableNames(newTables).ToArray()) + "'";
The method GetIDsForTableNames may also return an empty list containing no elements at all. In this case the resulting query from above would lead to something like this:
SELECT * from TABLE1 where ID NOT IN ('')
Which I expect to return ALL the IDs from TABLE1. But instead NONE is returned. However when I fire SELECT * from TABLE1 where ID NOT IN ('a') where a is just a dummy all rows from TABLE1 are returned.
So how can I handle the list-is-empty-case appropriatly or why doesn´t it work with an empty list?
EDIT: Okay, it seems some surroundings are not clear enough. As I´m not building the SQL-string self (this is done via 3rd-party tool), I can only modify the whereclause which is only some kind of minimzed SQL (subqueries and joins NOT supported). This is why I used the ID IN-technic.
why doesn´t it work with an empty list?
That's because of 2 things:
1. Oracle treats empty strings as null values
So your query:
SELECT * from TABLE1 where ID NOT IN ('')
is in fact equivalent to:
SELECT * from TABLE1 where ID NOT IN (NULL)
2. NOT IN behavior
The NOT IN clause can be simplified as a check of all values against the list.
If the result of any value is TRUE (the value is in the list) or NULL, then the test fails.
All the checks returns NULL, so your query doesn't return any row.
This is why it doesn't work with an empty list in Oracle.
Back to your question:
how can I handle the list-is-empty-case appropriatly
You have to find another way than getting the IDs and including them in a NOT IN clause.
As you don't have any control on the query, you will have to include details on your 3-party tool and hope there is a workaround.
More info about this:
Oracle/PLSQL: Difference between an empty string and a null value
Understand how NULLs affect IN and EXISTS
NULLs in Oracle
Note: (just in case some SQL Server users find this post)
If you were using SQL Server, your query would work because empty strings are not processed as NULL.
Even the second query SELECT * from TABLE1 where ID NOT IN (NULL) would work assuming you have set ANSI_NULLS to OFF. Such a setting is not available in Oracle.

Average a null columns in stored procedure

I have a stored procedure and I want to average null columns.
This is my stored procedure :
SELECT
AVG(planned) AS Planned,
AVG(achieved) AS Achieved
FROM
Port
INNER JOIN
Technology ON Port.portID = Technology.portRef
I bind this stored procedure to a chart using datasource and when the column is null the C# code throws this error:
Value was either too large or too small for a Decimal.
How can I handle my stored procedure to avg those null columns?
This happens when the query does not return any values. Use this
SELECT
coalesce(avg(planned),0) as Planned,
coalesce(avg(achieved),0) as Achieved
FROM
Port inner join Technology on Port.portID = Technology.portRef
another way
SELECT avg(isnull(planned,0))as Planned,avg(isnull(achieved,0)) as Achieved
FROM Port inner join Technology on Port.portID = Technology.portRef
I have seen several people getting confused whether to use ISNULL or COALESCE.
I would strongly recommend COALESCE. In some cases both will run fine, but in some cases ISNULL if not properly handled will give wrong output.
Please check the below snippet :
SELECT
ISNULL(Nullif('test', 'test'), '12345') AS using_isnull,
COALESCE(Nullif('test', 'test'), '12345') AS using_coalesce,
ISNULL(Nullif('test', 'test'), 12345) AS int_using_isnull,
COALESCE(Nullif('test', 'test'), 12345) AS int_using_coalesce
Use the keyword unpivot
select id, AVG(Q)
from (select * from myTable) a
unpivot(Q for QQ IN(Q1,Q2,Q3,Q4,Q5)) b
group by id
If all the columns are null, it won't return anything though.

Using C# to Select from SQL database Table

I have a List of UserID's and a open connection to SQL Server. How can I loop through this List and Select matching UserID with First_Name and Last_Name columns? I assume the output can be in a datatable?
many thanks
It varies slightly depending on which type of SQL you're running, but this and this should get you started.
The most expedient way of doing this would be to:
Turn the List into a string containing a comma separated list of the userid values
Supply that CSV string into an IN clause, like:
SELECT u.first_name,
u.last_name
FROM USER_TABLE u
WHERE u.userid IN ([comma separated list of userids])
Otherwise, you could insert the values into a temp table and join to the users table:
SELECT u.first_name,
u.last_name
FROM USER_TABLE u
JOIN #userlist ul ON ul.userid = u.userid
Write a function in your SQL database named ParseIntegerArray. This should convert a comma delimited string into a table of IDs, you can then join to this in your query. This also helps to avoid any SQL injection risk you could get from concatenating strings to build SQL. You can also use this function when working with LINQ to SQL or LINQ to Entities.
DECLARE #itemIds nvarchar(max)
SET itemIds = '1,2,3'
SELECT
i.*
FROM
dbo.Item AS i
INNER JOIN dbo.ParseIntegerArray(#itemIds) AS id ON i.ItemId = id.Id
This article should help you: http://msdn.microsoft.com/en-us/library/aa496058%28SQL.80%29.aspx
I've used this in the past to create a stored procedure accepting a single comma delimited varchar parameter.
My source from the C# program was a checked list box, and I built the comma delimited string using a foreach loop and a StringBuilder to do the concatenation. There might be better methods, depending on the number of items you have in your list though.
To come back to the SQL part, the fn_Split function discussed in the article, enables you to transform the comma delimited string back to a table variable that SQL Server can understand... and which you can query in your stored procedure.
Here is an example:
CREATE PROCEDURE GetSelectedItems
(
#SelectedItemsID Varchar(MAX) -- comma-separated string containing the items to select
)
AS
SELECT * FROM Items
WHERE ItemID IN (SELECT Value FROM dbo.fn_Split(#SelectedItemsIDs,','))
RETURN
GO
Note that you could also use an inner join, instead of the IN() if you prefer.
If you don't have the fn_Split UDF on your SQL Server, you can find it here: http://odetocode.com/Articles/365.aspx
I hope this helps.

Categories

Resources