SQL Query...nulls hosing me - sql

I tried to ask this question before but I don't think I explained myself very well. So here it is: asp.net 2.0 app hitting a SQL 2008 backend. This seems simple but I can't get it. 1 table. The user selects a status. The query should return all records = the chosen status only. If the user select "All Status", then ALL records should be returned, including those with a status = null (which is the part that is hosing me).
Ex:
CASE 1: User selects Status = "Satisfied"; ONLY satisfied records are return
CASE 2: User selects All Status = everything is returned, satisfied AND nulls and anything else
I tried passign in a wildcard but this doesn't return nulls. I tried dynamically buildign the query but I would like to avoid it.

For the case where you want them all, how about: (am I missing something?)
SELECT * FROM <tablename>

SELECT * FROM <tablename> WHERE Status = '*' OR Status IS NULL
...or '%' or whatever wildcard your SQL implementation uses.
...or if you really have no other conditions following this, just select *...

Try this in a stored procedure.
--Pass in #status as a parameter
DECLARE #Status varchar(100)
IF #Status = 'All Status'
BEGIN
SELECT * FROM tablename
END
ELSE
BEGIN
SELECT * FROM tablename where statusfield = #Status
END

One option is
declare #status varchar(50)
SELECT * FROM <tablename> WHERE (#status is null) or (Status = #status)
if you pass null in for the #status parameter then it will return all records. If you pass 'satisfied' or whatever then it will return just those matchng records.
If doing this in SQL 2008, be sure you have SP1 and Cumulative Update 5 installed. Further, I would recommend adding the WITH RECOMPILE option to the procedure. Under those conditions it will be as performant as embedded SQL or even using unions.
See the following article for an indepth discussion of the myriad of ways to perform searching in SQL 2008: Dynamic Search Conditions in T-SQL

The problem is that SQL's = operator always returns NULL when one of the operands is NULL, so using status = '%' indeed doesn't work. The best method is to just not include a condition on status if you want all of them. You can add extra NULL tests to the query, but that again is building it dynamically, I don't see a way to avoid that...

basically your statement will be for 'Statisfied'
SELECT * FROM testtab WHERE
COALESCE(statuscolumn, '') LIKE '%Statified'
for 'All Status' it will be
SELECT * FROM testtab WHERE
COALESCE(statuscolumn, '') LIKE '%'
you could use this statment and if selection is 'All Status' then pass a '' for the #status from your UI
SELECT * FROM testtab WHERE
COALESCE(statuscolumn, '') LIKE '%' || #status
Or you can use this one and when you pass the selection from UI make sure it has a '%' (wild char) appended to your status when it not 'All Status'. When its 'All Status' just pass '%' for the #status
SELECT * FROM testtab WHERE
COALESCE(statuscolumn, '') LIKE #status
oh your db is mssql? :) then you will need to replace the collace(statuscolumn, '') with isnull(statuscolumn, '').

Just skip the where clause or the part that is about the status field, example:
SELECT * from table_1 Where status = 'Satisfied'
and
SELECT * from table_1

When you want all records, you have to exclude STATUS from your WHERE clause (or use a UNION and a select statement where STATUS IS NULL).
Depending on what version of SQL you are using, you might be able to use an IF..ELSE... statement.
IF Status='ALL' THEN
... A SELECT statement where STATUS is NOT included in the WHERE
ELSE
... A SELECT statement that has a WHERE with only the status you are looking for

SELECT * FROM <tablename> WHERE isnull(Status,'*') = '*'

Assuming you're passing a variable to an SP:
SELECT * FROM Table WHERE Status CASE #status WHEN 'All status' THEN Status ELSE #status END
Otherwise, you need to concatenate in the selected value within quotes at both places where it currently says #status

The idea is what to do when the users chooses 'All Status'. By setting the param to NULL, you can use the isnull and then each [status] field just needs to equal itself. I've used ISNULL to set to '' to avoid having NULL = NULL>
declare #param_choice varchar(25)
if #param_choice = 'All Status'
Begin
#param_choice = NULL
End
-- get your results
Select * from Some_Table
Where IsNull([Status], '') = IsNull(#param_choice, IsNull([Status], ''))

You'll get the best performance from:
IF #status IS NULL
BEGIN
SELECT t.*
FROM TABLE t
END
ELSE
BEGIN
SELECT t.*
FROM TABLE t
WHERE t.status = #status
END
The next option is to use:
SELECT t.*
FROM TABLE t
WHERE (#status IS NULL OR t.status = #status)
...but that is not sargable.

I do not believe that anyone suggested using a UNION.
SELECT t.*
FROM TABLE t
WHERE (#status IS NULL)
UNION ALL
SELECT t.*
FROM TABLE t
WHERE (t.status = #status)
If #status is NULL, then the first query in the union is executed, and t.status = #status is clearly always false, so the second query in the union is not executed at all.
If #status is not null, then the first query in the union is not exected at all, and the second one is.
Importantly, since ISNULL, COALESCE or a function are not used on t.status or on #status, then if there is an index on status, it can be used. That is, the predicate is SARGABLE.
And I used UNION ALL (instead of UNION) to prevent a SORT and DISTINCT operation that can be very slow.

Related

Execute a stored procedure within a case statement

I have an Insert Into Select statement with a Case When clause. I want to execute a stored procedure within the When statement.
Insert into Orders(id, custId, custIntake)
Select id, custId custIntake =
Case
When ( Exec mySProc(custId) = 1 ) = 'InStore'
When ( Exec mySProc(custId) = 0 ) = 'OutsideStore'
Else null
End
From OrdersImport
How can I run Exec mySProc(custId) within the Case When?
I would suggest you convert your 'mySProc' procedure into a Scalar User Defined Function if you want to run it like this. Stored Procedures are not able to do what you want.
If I understand correctly then what you need is code to run when the WHEN statement is true.
Just use CASE > WHEN > THEN as described here: http://msdn.microsoft.com/en-us/library/ms181765.aspx
Hope this helps.
Do like this.
If you set auto increment for id column, not need to mention in the query. If you need, you can add it.
Insert into orders(custId, custIntake)
Select custId, (CASE WHEN custId = '1' THEN 'InsideStore' ELSE 'OutsideStore' END) from ordersimport;
Hope, it will help you.

T-SQL: WHERE Clause - How to adjust based on input variable

Using SQL Server 2008. I have an input param in my stored proc called '#State'. The param can basically be '--All--' or can contain the state to filter.
So, if it is '--All--' I don't want to incorporate the #State into the where clause. Otherwise I'd like it to filter based on the provided #State. So basically it could result in this....
SELECT * FROM MyTable
WHERE Type='AAA' AND Status=#Status
or, if they pass '--All--'
SELECT * FROM MyTable
WHERE Type='AAA'
How can I do this in a stored proc?
SELECT
*
FROM
MyTable
WHERE
Type='AAA'
AND Status = CASE #Status WHEN '--All--' THEN Status ELSE #Status END
I thought you made a typo. It should be #State, not #Status. This simple query might not be what you are looking for since you want to two sql statements in your requirement.
SELECT * FROM MyTable
WHERE Type='AAA' AND (#State='--All--' or State=#State)
Or...
you could make it even simpler than that:
SELECT * FROM MyTable
WHERE Type='AAA' AND #State in ('--All--', State)
No need to do it in a stored procedure, unless absolutely necessary (or if business/coding practice requires you to do so).

sql query - get all records based on a flag

Apologies for creating a new thread. I was not able to frame the question correctly in the previous thread.
I have a table in SQL Server 2008 that looks like this -
Id Status
--------------
1 A
2 I
3 NULL
I have a stored procedure which takes #Status as the parameter.
If the #Status is "-1", I need to retrieve records 1, 2.
If the #Status is "A", I need to retrieve only record 1.
If the #Status is "I", I need to retrieve only record 2.
I want to be able to retrieve the records in a single SELECT statement without using IF ELSE. There are a lot of joins and stuff in the SELECT statement and I don't want to repeat the same thing in the ELSE condition.
I have tried the following but get incorrect data -
SELECT * FROM Person WHERE Status = #Status OR #Status IS NOT NULL
select * from Person
where (#Status is not null and Status = #Status) or
(#Status is null and Status in ('A', 'P'))
You can do it using OR:
SELECT *
FROM Person
WHERE Status = #Status
OR (#Status = '-1' AND Status IS NOT NULL)
Of course you shouldn't use SELECT * in production code.

Nested if statements in SQL Server stored procedure SELECT statement

I'm new here, and relatively new to stored procedures, so please bear with me! I've checked related questions on here and can't find anything that works in this instance.
I am trying to build a stored procedure (MS SQL Server 2005) that takes a number of passed in values and in effect dynamically builds up the SQL as you would with inline SQL.
This is where I've come unstuck.
We have (somewhat simplified for clarity):
#searchf1 varchar(100), -- search filter 1
#searchr1 varchar(100), -- search result 1
#searchf2 varchar(100), -- search filter 2
#searchr2 varchar(100), -- search result 2
#direction char(1), -- direction to order results in
AS
set nocount on
set dateformat dmy
SELECT *
FROM database.dbo.table T
WHERE T.deleted = 'n'
ORDER BY CASE #direction
WHEN 'A' THEN T.id
WHEN 'D' THEN T.id DESC
END
END
set nocount off
I have also tried the lines from ORDER BY as:
IF #direction = 'N' THEN
ORDER BY
T.id
ELSE
ORDER BY
T.id DESC
Both approaches give me an error along the lines:
"Incorrect syntax near the keyword 'DESC'." (which references the line id DESC following the final ORDER BY
As part of this stored procedure I also want to try to feed in matched pairs of values which reference a field to look up and a field to match it to, these could either be present or ''. To do that I need to add into the SELECT section code similar to:
WHERE
deleted = 'n'
IF #searchf1 <> '' THEN
AND fieldf1 = #searchf1 AND fieldr1 = #searchr1
This however generates errors like:
Incorrect syntax near the keyword 'IF'.
I know dynamic SQL of this type isn't the most elegant. And I know that I could do it with glocal IF ELSE statements, but if I did the SP would be thousands of lines long; there are going to up to 15 pairs of these search fields, together with the direction and field to order that direction on.
(the current version of this SP uses a passed in list of IDs to return generated by some inline dynamic SQL, through doing this I'm trying to reduce it to one hit to generate the recordset)
Any help greatly appreciated. I've hugely simplified the code in the above example for clarity, since it's the general concept of a nested IF statement with SELECT and ORDER BY that I'm inquiring about.
For this I would try to go with a more formal Dynamic SQL solution, something like the following, given your defined input parameters
DECLARE #SQL VARCHAR(MAX)
SET #SQL = '
SELECT
FROM
database.dbo.table T
WHERE
T.deleted = ''n'' '
--Do your conditional stuff here
IF #searchf1 <> '' THEN
SET #SQL = #SQL + ' AND fieldf1 = ' + #searchf1 + ' AND fieldr1 = ' + #searchr1 + ''' '
--Finish the query
SET #SQL = #SQL + ' ORDER BY xxx'
EXEC(#SQL)
DISCLAIMER: The use of Dynamic SQL is NOT something that should be taken lightly, and proper consideration should be taken in ALL circumstances to ensure that you are not open to SQL injection attacks, however, for some dynamic search type operations it is one of the most elegant route.
Try it this way:
SELECT * FROM database.dbo.table T WHERE T.deleted = 'n'
ORDER BY
CASE WHEN #direction='A' THEN T.id END ASC,
CASE WHEN #direction='D' THEN T.id END DESC
Source Article:
http://blog.sqlauthority.com/2007/07/17/sql-server-case-statement-in-order-by-clause-order-by-using-variable/
Another option that you might have, depending on the data type of your field, if nulls are NOT allowed, would be to do something like this.
SELECT *
FROM database.dbo.table T
WHERE T.deleted = 'n'
AND fieldf1 = COALESCE(#searchf1, fieldf1)
AND fieldr1 = COALESCE(#searchr1, fieldr1)
--ETC
ORDER BY fieldf1
This way you are not using dynamic SQL and it is fairly readable, just have the variable be null when you are looking to omit the data.
NOTE: As I mentioned this route will NOT work if any of the COALESCE columns contain null values.

In SQL, how do I allow for nulls in the parameter?

I have what seems to be a really easy SQL query I can't figure out and its driving me nuts. This is SQL 2008. Basically, there is a status field where the can pick "pending", "satisfied" or all. If they send in "pending" or "satisfied" there's no problem. But when they pick all I'm having problems. Mostly because I can't figure out how to get the records where this field is null to show up (because it has to be 'is null' instead of '= null'. (This is the way the data will come over; I have no control over that.)
The code I've been using does not work for nulls.
SELECT *
FROM Payment_Table
where Payment.Status_code = #status_id
You can try
SELECT Col1, Col2,...,Coln --Required Columns
FROM Payment_Table
where (Payment.Status_code = #status_id OR #status_id IS NULL)
Try:
SELECT *
FROM Payment_Table
WHERE Payment.Status_code = ISNULL(#status_id, Status_code)
This will return all payments.
Try
WHERE
((#status_id IS NULL) OR (Payment.Status_code = #status_id))
WHERE Payment_Table.Status = ISNULL(#StatusID, Payment_Table.Status)
It usually works better then OR
Edit: you want to select rows where Payment_Table.Status = NULL when #StatusID = NULL!!
SELECT * FROM Payment_Table where Payment.Status_code = #status_id
UNION ALL
SELECT * FROM Payment_Table where Payment.Status_code IS NULL AND #StatusID IS NULL
OR
...
WHERE
Payment_Table.Status #StatusID
OR
(Payment.Status_code IS NULL AND #StatusID IS NULL)
You can use coalesce or IsNull on your Payment.StatusCode field, this will allow you to do a substitution for null with a specific value.
SELECT *
FROM Payment_Table
WHERE (Payment.Status_code is null or Payment.Status_code = #status_id)
There are many approaches depending which version of sql server you are using. This articles has an in-depth description: Dynamic Search Conditions in T-SQL
The best way to do this is below. However, you MUST watch out for parameter sniffing. This will become an issue as your table gets bigger and will affect your execution times randomly. This is an annoying issue that can pop up. Use the code below.
CREATE PROCEDURE GetPaymentStatus
#StatusID varchar(50)=NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #StatusId_local varchar(50)
SET #StatusID_local = #StatusId
SELECT MyField1, MyField2
FROM Payment_Table
WHERE Payment_Table.Status=#StatusID_local
OR (#StatusID_local IS NULL AND Payment_Table.Status IS NULL)
END
Check out this article or google sql parameter sniffing for more info.