CASE statement within WHERE clause in SQL Server 2008 - sql-server

I want to write a CASE statement to find the data between two dates based on #sFRomDate empty or not. Given below query not working as per my requirement. Please help me to find a proper solution
SELECT
*
FROM
tbl_emp_data
WHERE
CASE
WHEN #sFRomDate!=''
THEN SubmissionDate BETWEEN #sFRomDate AND DATEADD(DAY,1,#sToDate)
ELSE
SubmissionDate = NULL
END

This might be the logic you were trying to implement. In the event that #sFRomDate be NULL or empty and SubmissionDate also be NULL or empty the record will be returned. Otherwise, the SubmissionDate will be checked to make sure it is within the range you defined.
SELECT *
FROM tbl_emp_data
WHERE (COALESCE(#sFRomDate, '') = '' AND
COALESCE(SubmissionDate, '') = '') OR
(COALESCE(#sFRomDate, '') <> '' AND
COALESCE(SubmissionDate, '') <> '' AND
SubmissionDate BETWEEN #sFRomDate AND DATEADD(DAY, 1, #sToDate))

If I understand what you want, I think it becomes simpler to follow the logic if you write:
IF #sFromDate = ''
BEGIN
SELECT * FROM tbl_emp_data where SubmissionDate=null
END
ELSE
BEGIN
SELECT * FROM tbl_emp_data where SubmissionDate between #sFRomDate and DATEADD(DAY,1,#sToDate)
END
But as #Tim Biegeleisen says, be careful with nulls, not just for #sFromDate but also #sToDate

Related

Which is faster (ISNULL(#SKU, '') = '') or (#SKU IS NULL OR #SKU = '')

There is one if case where I am using IF #SKU IS NULL OR #SKU = '', but my friend says it will take more time as compare to IF ISNULL(#SKU, '') = ''. So you should use IF ISNULL(#SKU, '') = ''. But I think I'm using correct. So please suggest me which one is run faster.
This is my stored procedure:
CREATE PROCEDURE USP_GetExistingRefunds
(
#OrderNo VARCHAR(50),
#SKU VARCHAR(255),
#ProfileID INT
)
AS
BEGIN
--IF ISNULL(#SKU, '') = '' --this work faster or
IF #SKU IS NULL OR #SKU = '' --this work faster
BEGIN
SELECT OrderNo, SKU, ISNULL(Quantity, 0) Quantity, ISNULL(Amount, 0) Amount
FROM StoreRefundOrder SRO
INNER JOIN StoreRefundOrderItem SROI ON SRO.ID = SROI.RefundOrderID
WHERE SRO.OrderNo = #OrderNo
AND ProfileID = #ProfileID
END
ELSE
BEGIN
SELECT OrderNo, SKU, ISNULL(SUM(Quantity), 0) Quantity, ISNULL(SUM(Amount), 0) Amount
FROM StoreRefundOrder SRO
INNER JOIN StoreRefundOrderItem SROI ON SRO.ID = SROI.RefundOrderID
WHERE SRO.OrderNo = #OrderNo
AND SROI.SKU = #SKU
AND ProfileID = #ProfileID
GROUP BY OrderNo, SKU
END
END
In the context of an IF/ELSE Procedural batch
It doesn't make any difference whatsoever. It literally takes 0.00 MS to determine if a value is blank or unknown, it takes the 0.00MS to determine if ISNULL(#SKU, '') = ''. If there is a difference it would likely be measured in nanoseconds IMO. Again, this in the context of a procedural batch because the statement is only being evaluated once.
In the context of an FILTER (e.g. ON, WHERE or HAVING CLAUSE)
Here the difference is actually enormous, it cannot be understated. This is tricky to explain with parameters and variables involved, so, for brevity, I show you an example with this sample data:
IF OBJECT_ID('tempdb..#things','U') IS NOT NULL DROP TABLE #things;
SELECT TOP (10000) Txt = SUBSTRING(LEFT(NEWID(),36),1,ABS(CHECKSUM(NEWID())%x.N))
INTO #things
FROM (VALUES(1),(30),(40),(NULL)) AS x(N)
CROSS JOIN sys. all_columns;
UPDATE #things SET Txt = NEWID() WHERE txt = '0';
CREATE NONCLUSTERED INDEX nc_things1 ON #things(Txt);
The following queries will find rows that either do or do not contain blanks or nulls
-- Finding things that are blank or NULL
SELECT t.Txt
FROM #things AS t
WHERE t.Txt IS NULL OR t.Txt = '';
-- Finding things that are NOT blank or NULL
SELECT t.Txt
FROM #things AS t
WHERE NOT(t.Txt IS NULL OR t.Txt = '');
SELECT t.Txt
FROM #things AS t
WHERE t.Txt > '';
-- Finding things that are blank or NULL
SELECT t.Txt
FROM #things AS t
WHERE ISNULL(t.Txt,'') = '';
-- Finding things that are NOT blank or NULL
SELECT t.Txt
FROM #things AS t
WHERE ISNULL(t.Txt,'') <> '';
The first three queries are SARGable, the last two are not because of ISNULL. Even though there's an index to help me, the ISNULL renders it useless here. It's the difference between asking someone to look in a phone book for everyone whose name begins with "A" and finding everyone who's name ends with "A".
SARGable predicates allow a query to seek a portion of an index where non-SARGable predicates force a query to scan the entire table REGARDLESS of the how many matching rows exist (if any). When you are dealing with millions/billions of rows joined to many other tables the difference can be a query that runs in seconds to one that, in some cases, may run for hours or even weeks (I've seen a few).
EXECUTION PLANS:
Note that this last one WHERE t.Txt > '' will work too. Any non-null text value is > '' and if t.Txt was NULL then it will also evaluate to false. I include this because this expression works for filtered indexes. The only catch is you can't use it on a text field where Implicit conversion can transform this into the number 0 or less. Note these queries:
IF '' = 0 PRINT 'True' ELSE PRINT 'False'; -- Returns True
IF '' = '0' PRINT 'True' ELSE PRINT 'False'; -- Returns False
IF '' > -1 PRINT 'True' ELSE PRINT 'False'; -- Returns True
IF '' > '-1' PRINT 'True' ELSE PRINT 'False'; -- Returns False
IF #SKU IS NULL OR #SKU ='' is checking null and blank both. In second case if Isnull(#sku,'') you are checking null and assigning '' for null value. Both are different cases.
Which is faster (ISNULL(#SKU, '') = '') or (#SKU IS NULL OR #SKU =
'')
It really doesn't matter in this case. If you were comparing against a column then (SKU IS NULL OR SKU = '') would be preferable as it can use an index but any difference for a single comparison against a variable will be in the order of microseconds and dwarfed by the execution times of the SELECT statements.
To simplify the IF statement I'd probably invert it anyway as below
IF #SKU <> '' --Not null or empty string
BEGIN
SELECT OrderNo, SKU, ISNULL(SUM(Quantity), 0) Quantity, ISNULL(SUM(Amount), 0) Amount
FROM StoreRefundOrder SRO
INNER JOIN StoreRefundOrderItem SROI ON SRO.ID = SROI.RefundOrderID
WHERE SRO.OrderNo = #OrderNo
AND SROI.SKU = #SKU
AND ProfileID = #ProfileID
GROUP BY OrderNo, SKU
END
ELSE
BEGIN
SELECT OrderNo, SKU, ISNULL(Quantity, 0) Quantity, ISNULL(Amount, 0) Amount
FROM StoreRefundOrder SRO
INNER JOIN StoreRefundOrderItem SROI ON SRO.ID = SROI.RefundOrderID
WHERE SRO.OrderNo = #OrderNo
AND ProfileID = #ProfileID
END
A little long for a comment.
As has been noted by many already, in this case your two options don't really make any appreciable difference. But in the future, when you think of a couple of different ways to code something, there are standard practices you can implement quickly and easily to test for yourself.
At the top of your code block, add this command:
SET STATISTICS TIME, IO ON;
You can use either TIME or IO, but I almost always want to see both, so I always turn them both on at the same time.
The output from this addition will show up in your Messages window after your query or queries run and will give you tangible information about which method is faster, or causes less stress on the SQL Server engine.
You'll want to run a few tests with each option. Warm cache / cold cache especially, but a few iterations is best one way or the other to get an average or eliminate outlier results.
I'm weird, so I always close my code block with:
SET STATISTICS TIME, IO OFF;
But strictly speaking that's unnecessary. I just have a thing about resetting anything I change, just to avoid any possibility of forgetting to reset something that will matter.
Kendra Little has an informative blog post on using STATISTICS.

Append the previous value of a column in most optimized way without using case

Below is my T-SQL
Update Table1
Set Note = CONCAT(Note, ', ', #Note)
If in the above query Note is null or empty I want to avoid appending in that case
my query should behave like
Update Table1
Set Note=#Note
I think there are better and optimized way to do this so just searching for that option. I can write the query using case.
You could use coalesce because when using the + operator any null results in null as opposed to concat which handles null values as an empty string.
update Table1 set Note = coalesce(Note + ', ' + #Note, #Note)
But this doesn't handle the case when Note is an empty string. You need a case expression for that.
Actually you can handle the empty string case as follows:
update Table1 set Note = coalesce(nullif(Note,'') + ', ' + #Note, #Note)
But in my opinion that is more complex than using a simple case expression:
update Table1 set
Note = case when coalesce(Note,'') <> '' then concat(Note, ', ', #Note) else #Note end
The case expression is an integral part of T-SQL so I wouldn't be concerned about using it.
Further: NULLIF is actually a case under the hood anyway.
Similar to Dale K's 1st answer:
Update Table1 Set Note = CONCAT(NULLIF(Note, '') + ', ', #Note)
Parts explained:
NULLIF(Note, '') is used to turn an empty Note into NULL.
NULL + 'something' evaluates to: NULL.
CONCAT(NULL, 'something') evaluates to : 'something'.

Why the result is still null after placing the condition also? [duplicate]

I wrote a T-SQL Statement similar like this (the original one looks different but I want to give an easy example here):
SELECT first_name +
CASE last_name WHEN null THEN 'Max' ELSE 'Peter' END AS Name
FROM dbo.person
This Statement does not have any syntax errors but the case-clause always chooses the ELSE-part - also if the last_name is null. But Why?
What I want to do is to unite first_name and last_name, but if last_name is null the whole name becomes null:
SELECT first_name +
CASE last_name WHEN null THEN '' ELSE ' ' + last_name END AS Name
FROM dbo.person
Do you know where the problem is?
CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END
The WHEN part is compared with ==, but you can't really compare with NULL. Try
CASE WHEN last_name is NULL THEN ... ELSE .. END
instead or COALESCE:
COALESCE(' '+last_name,'')
(' '+last_name is NULL when last_name is NULL, so it should return '' in that case)
There are plenty of solutions but none covers why the original statement doesn't work.
CASE last_name WHEN null THEN '' ELSE ' '+last_name
After the when, there is a check for equality, which should be true or false.
If one or both parts of a comparison is null, the result of the comparison will be UNKNOWN, which is treated like false in a case structure. See: https://www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/
To avoid this, Coalesce is the best way.
Given your query you can also do this:
SELECT first_name + ' ' + ISNULL(last_name, '') AS Name FROM dbo.person
The problem is that null is not considered equal to itself, hence the clause never matches.
You need to check for null explicitly:
SELECT CASE WHEN last_name is NULL THEN first_name ELSE first_name + ' ' + last_name
try:
SELECT first_name + ISNULL(' '+last_name, '') AS Name FROM dbo.person
This adds the space to the last name, if it is null, the entire space+last name goes to NULL and you only get a first name, otherwise you get a firts+space+last name.
this will work as long as the default setting for concatenation with null strings is set:
SET CONCAT_NULL_YIELDS_NULL ON
this shouldn't be a concern since the OFF mode is going away in future versions of SQl Server
The issue is that NULL is not considered to be equal to anything even not to itself, but the strange part is that is also not not equal to itself.
Consider the following statements (which is BTW illegal in SQL Server T-SQL but is valid in My-SQL, however this is what ANSI defines for null, and can be verified even in SQL Server by using case statements etc.)
SELECT NULL = NULL -- Results in NULL
SELECT NULL <> NULL -- Results in NULL
So there is no true/false answer to the question, instead the answer is also null.
This has many implications, for example in
CASE statements, in which any null value will always use the ELSE clause unless you use explicitly the WHEN IS NULL condition (NOT the WHEN NULL condition )
String concatenation, as
SELECT a + NULL -- Results in NULL
In a WHERE IN or WHERE NOT IN clause, as if you want correct results make sure in the correlated sub-query to filter out any null values.
One can override this behavior in SQL Server by specifying SET ANSI_NULLS OFF, however this is NOT recommended and should not be done as it can cause many issues, simply because deviation of the standard.
(As a side note, in My-SQL there is an option to use a special operator <=> for null comparison.)
In comparison, in general programming languages null is treated is a regular value and is equal to itself, however the is the NAN value which is also not equal to itself, but at least it returns 'false' when comparing it to itself, (and when checking for not equals different programming languages have different implementations).
Note however that in the Basic languages (i.e. VB etc.) there is no 'null' keyword and instead one uses the 'Nothing' keyword, which cannot be used in direct comparison and instead one needs to use 'IS' as in SQL, however it is in fact equal to itself (when using indirect comparisons).
Found a solution to this. Just ISNULL the CASE statement:
ISNULL(CASE x WHEN x THEN x ELSE x END, '') AS 'BLAH'
CASE
WHEN last_name IS null THEN ''
ELSE ' ' + last_name
END
Jason caught an error, so this works...
Can anyone confirm the other platform versions?
SQL Server:
SELECT
CASE LEN(ISNULL(last_name,''))
WHEN 0 THEN ''
ELSE ' ' + last_name
END AS newlastName
MySQL:
SELECT
CASE LENGTH(IFNULL(last_name,''))
WHEN 0 THEN ''
ELSE ' ' + last_name
END AS newlastName
Oracle:
SELECT
CASE LENGTH(NVL(last_name,''))
WHEN 0 THEN ''
ELSE ' ' + last_name
END AS newlastName
When you get frustrated trying this:
CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END
Try this one instead:
CASE LEN(ISNULL(last_Name,''))
WHEN 0 THEN ''
ELSE ' ' + last_name
END AS newlastName
LEN(ISNULL(last_Name,'')) measures the number of characters in that column, which will be zero whether it's empty, or NULL, therefore WHEN 0 THEN will evaluate to true and return the '' as expected.
I hope this is a helpful alternative.
I have included this test case for sql server 2008 and above:
DECLARE #last_Name varchar(50) = NULL
SELECT
CASE LEN(ISNULL(#last_Name,''))
WHEN 0 THEN ''
ELSE 'A ' + #last_name
END AS newlastName
SET #last_Name = 'LastName'
SELECT
CASE LEN(ISNULL(#last_Name,''))
WHEN 0 THEN ''
ELSE 'A ' + #last_name
END AS newlastName
I tried casting to a string and testing for a zero-length string and it worked.
CASE
WHEN LEN(CAST(field_value AS VARCHAR(MAX))) = 0 THEN
DO THIS
END AS field
You can use IsNull function
select
isnull(rtrim(ltrim([FirstName]))+' ','') +
isnull(rtrim(ltrim([SecondName]))+' ','') +
isnull(rtrim(ltrim([Surname]))+' ','') +
isnull(rtrim(ltrim([SecondSurname])),'')
from TableDat
if one column is null you would get an empty char
Compatible with Microsoft SQL Server 2008+
Use the CONCAT function available in SQL Server 2012 onward.
SELECT CONCAT([FirstName], ' , ' , [LastName]) FROM YOURTABLE
NULL does not equal anything. The case statement is basically saying when the value = NULL .. it will never hit.
There are also several system stored procedures that are written incorrectly with your syntax. See sp_addpullsubscription_agent and sp_who2.
Wish I knew how to notify Microsoft of those mistakes as I'm not able to change the system stored procs.
In SQL Server 2017, Microsoft introduced a Concatenate With Separator function, for just your situation:
SELECT CONCAT_WS(' ', first_name, last_name) FROM dbo.person
CONCAT_WS skips NULL values, but not empty strings.
Interestingly, MySQL introduced CONCAT_WS over a decade earlier.
You can use like this:
CASE IsNull(last_name,'') WHEN '' THEN 'Max' ELSE 'Peter' END AS Name

Adding Dyanmic In() Conditions in Sql Server

Facing problem for generating SQL Server Query
In the Following query dynamic conditions are added to check whether value is null or not
Select *
From tblEmployees
where EmployeeName = Case
When #EmployeeName Is Not Null
Then #EmployeeName
Else EmployeeName
End
But I need to add IN () Conditions and the parameter with in the IN () could be null or blank also ,if the parameter /string which is passed to the IN condition is blank then i donot want to add that condition in the query.
So how can i Achieve this.A helping hand will be very useful for me.
Thanks and Regards,
D.Mahesh
Depending on value of your parameter (blank of not), you can create SQL string accordingly.
DECLARE #sqlCommand VARCHAR(1000)
IF(ISNULL(#YourParameter,'')='')
#sqlCommand = 'your query goes here'
ELSE
#sqlCommand = 'your query goes here'
and then, run it using dynamic query execution
EXEC (#sqlCommand)
If not dynamic query then,
SELECT ....
FROM ....
WHERE CASE WHEN ISNULL(#YourParameter,'')='' THEN '' ELSE EmployeeName END IN (ISNULL(#YourParameter,''))
See if this works...
I think the Dynamic query is the best solution, however you could put the "IS NULL" and "IS BLANK" condition in OR with your IN clause.
Something like that
Select *
From tblEmployees
where #EmployeeName is null or EmployeeName in (#EmployeeName)
When #EmployeeName is null, your IN clause will be ignored
If i get this right you have #EmployeeName = 'Name1,Name2,Name3' and you want to get the employees that is named Name1 or Name2 or Name3, also the variable #EmployeeName can be null or contain an empty string.
Instead of using IN you can split the string #EmployeeName on , and store it in a table variable or temporary table. Then you can use that table in a join against tblEmployees to get the rows you need.
There are a lot of posts in S.O. about how to split a string. Here is one recent variant.
Group by sql query on comma joined column
This will work for SQL Server 2005 or later.
declare #EmployeeName varchar(100) = 'Name2,Name3,Name5'
-- Null or empty will have a comma
set #EmployeeName = coalesce(#EmployeeName, '') + ','
-- cteNames splits the string to rows
;with cteNames
as
(
select
left(#EmployeeName, charindex(',', #EmployeeName)-1) as Name,
right(#EmployeeName, len(#EmployeeName)-charindex(',', #EmployeeName)) as EmployeeName
union all
select
left(EmployeeName, charindex(',', EmployeeName)-1) as Name,
right(EmployeeName, len(EmployeeName)-charindex(',', EmployeeName)) as EmployeeName
from cteNames
where charindex(',', EmployeeName) > 1
)
select E.*
from tblEmployees as E
inner join cteNames as N
on E.Name = N.Name or
#EmployeeName = ','
-- #EmployeeName = ',' will give you all names when #EmployeeName is null of empty

How do I check if a SQL Server text column is empty?

I am using SQL Server 2005. I have a table with a text column and I have many rows in the table where the value of this column is not null, but it is empty. Trying to compare against '' yields this response:
The data types text and varchar are incompatible in the not equal to operator.
Is there a special function to determine whether the value of a text column is not null but empty?
where datalength(mytextfield)=0
ISNULL(
case textcolum1
WHEN '' THEN NULL
ELSE textcolum1
END
,textcolum2) textcolum1
Actually, you just have to use the LIKE operator.
SELECT * FROM mytable WHERE mytextfield LIKE ''
To get only empty values (and not null values):
SELECT * FROM myTable WHERE myColumn = ''
To get both null and empty values:
SELECT * FROM myTable WHERE myColumn IS NULL OR myColumn = ''
To get only null values:
SELECT * FROM myTable WHERE myColumn IS NULL
To get values other than null and empty:
SELECT * FROM myTable WHERE myColumn <> ''
And remember use LIKE phrases only when necessary because they will degrade performance compared to other types of searches.
SELECT * FROM TABLE
WHERE ISNULL(FIELD, '')=''
Use the IS NULL operator:
Select * from tb_Employee where ename is null
I know this post is ancient but, I found it useful.
It didn't resolve my issue of returning the record with a non empty text field so I thought I would add my solution.
This is the where clause that worked for me.
WHERE xyz LIKE CAST('% %' as text)
Use DATALENGTH method, for example:
SELECT length = DATALENGTH(myField)
FROM myTABLE
Instead of using isnull use a case, because of performance it is better the case.
case when campo is null then '' else campo end
In your issue you need to do this:
case when campo is null then '' else
case when len(campo) = 0 then '' else campo en
end
Code like this:
create table #tabla(
id int,
campo varchar(10)
)
insert into #tabla
values(1,null)
insert into #tabla
values(2,'')
insert into #tabla
values(3,null)
insert into #tabla
values(4,'dato4')
insert into #tabla
values(5,'dato5')
select id, case when campo is null then 'DATA NULL' else
case when len(campo) = 0 then 'DATA EMPTY' else campo end
end
from #tabla
drop table #tabla
I would test against SUBSTRING(textColumn, 0, 1)
Are null and an empty string equivalent? If they are, I would include logic in my application (or maybe a trigger if the app is "out-of-the-box"?) to force the field to be either null or '', but not the other. If you went with '', then you could set the column to NOT NULL as well. Just a data-cleanliness thing.
I wanted to have a predefined text("No Labs Available") to be displayed if the value was null or empty and my friend helped me with this:
StrengthInfo = CASE WHEN ((SELECT COUNT(UnitsOrdered) FROM [Data_Sub_orders].[dbo].[Snappy_Orders_Sub] WHERE IdPatient = #PatientId and IdDrugService = 226)> 0)
THEN cast((S.UnitsOrdered) as varchar(50))
ELSE 'No Labs Available'
END
You have to do both:
SELECT * FROM Table WHERE Text IS NULL or Text LIKE ''
I know there are plenty answers with alternatives to this problem, but I just would like to put together what I found as the best solution by #Eric Z Beard & #Tim Cooper with #Enrique Garcia & #Uli Köhler.
If needed to deal with the fact that space-only could be the same as empty in your use-case scenario, because the query below will return 1, not 0.
SELECT datalength(' ')
Therefore, I would go for something like:
SELECT datalength(RTRIM(LTRIM(ISNULL([TextColumn], ''))))
try this:
select * from mytable where convert(varchar, mycolumn) = ''
i hope help u!
DECLARE #temp as nvarchar(20)
SET #temp = NULL
--SET #temp = ''
--SET #temp = 'Test'
SELECT IIF(ISNULL(#temp,'')='','[Empty]',#temp)
It will do two things:
Null check and string null check
Replace empty value to default value eg NA.
SELECT coalesce(NULLIF(column_name,''),'NA') as 'desired_name') from table;

Resources