Check column IS NULL not working in Case Expression - sql

I am trying to check a column which belongs to View "IS NULL" and it works good with select statement:
SELECT TOP (1000) [Invoice_Number]
,[Invoice_Date]
,[Invoice_Amount]
,[Invoice_CoCd]
,[Invoice_vendor]
,[Invoice_PBK]
,[Invoice_DType]
,[Invoice_DueDate]
,[Invoice_ClgDate] FROM [dbo].[viewABC] where Invoice_PBK IS NULL
Now I have an update statement, where I need to update a column in a table based on NULL in VIEW:
UPDATE cis
SET
cis.InvoiceStatus =
(
CASE
WHEN RTRIM(LTRIM(imd.[Invoice_PBK])) IS NULL THEN
'HELLO'
WHEN RTRIM(LTRIM(imd.Invoice_DType)) = 'RD'
THEN '233' END)
FROM
[dbo.[tblABC] cis,
[dbo].[viewABC] imd
WHERE [condition logic]
These is no issue with where condition, the IS NULL in the CASE expression causing the problem.
Can someone help please?

You may want to just test your Logic piece by piece.
Try
SELECT ISNULL(RTRIM(LTRIM(imd.[Invoice_PBK])),'Hey Im Null')
FROM
[dbo].[tblABC] cis,
[dbo].[viewABC] imd
WHERE [condition logic]
See if you get that String value on your returned column(s) from the Query. Then, build from there. It could be something as simple as the JOIN. Which I'm not a fan of that old syntax but, without more info on this table other than [conditions]. It's hard to just guess an answer for you. You have no detailed evidence that helps us. It very well could be your conditions but, you're saying "condition logic" and that does nothing for the group on this thread.

Looking at this expression:
cis.InvoiceStatus =
CASE
WHEN RTRIM(LTRIM(imd.[Invoice_PBK])) IS NULL THEN
'HELLO'
WHEN RTRIM(LTRIM(imd.Invoice_DType)) = 'RD' THEN
'233'
END
And this symptom:
CIS.InvoiceStatus gets updated with NULL
The obvious conclusion is neither WHEN condition is met, and therefore the result of the CASE expression is NULL.
Maybe you wanted this, which will preserve the original value in that situation:
cis.InvoiceStatus =
CASE
WHEN RTRIM(LTRIM(imd.[Invoice_PBK])) IS NULL THEN
'HELLO'
WHEN RTRIM(LTRIM(imd.Invoice_DType)) = 'RD' THEN
'233'
ELSE
cis.InvoiceStatus
END
Or maybe you wanted this, to also match an empty string value:
cis.InvoiceStatus =
CASE
WHEN NULLIF(RTRIM(LTRIM(imd.[Invoice_PBK])),'') IS NULL THEN
'HELLO'
WHEN RTRIM(LTRIM(imd.Invoice_DType)) = 'RD' THEN
'233'
END
It's also worth pointing out the two WHEN conditions are looking at two different columns.
Finally, it may be worth a data clean-up project here. Needing to do an LTRIM() will break any chance of using indexes on those fields (RTRIM() is slightly less bad), and index use cuts to the core of database performance.

Related

SQL Using CASE to Apply WHERE [duplicate]

This question already has answers here:
SQL Server : check if variable is Empty or NULL for WHERE clause
(6 answers)
Closed 6 months ago.
I'm not sure if CASE is what I actually need to use here, but basically what I am trying to do is apply "WHERE ba.batchid = #batchId" but only if #batchId is not null.
Basically something like this, but this gives an error around the ba.batchid = '2' area ('2' is what the #batchId would come out to).
CASE WHEN '2' != '' THEN ba.batchid = '2' ELSE null END
It helps to think of Case statements as a scalar value. The problem you are experiencing is caused by doing a comparison within the case statement. Basically, you need to pull the comparison out of the case statement.
I'm not sure of the logic you are trying to use, but the following syntax should be correct.
CASE WHEN '2' != '' THEN ba.batchid ELSE null END = '2'
Note that the = '2' is moved to the end. This way, the case statement will return batchid or null depending on the WHEN statement. This value is then compared to '2'.
Try this:
WHERE NULLIF(#batchId, '') IS NOT NULL AND ba.batchid = #batchid
First condition avoids empty('') as well as NULL with #batchid. Second will match the table value.
Take it out of the SELECT part of your statement entirely and put it in the WHERE clause (after FROM)
WHERE ba.batchid = #batchId
AND ba.batchid IS NOT NULL
Note that the AND ba.batchid IS NOT NULL is not necessary here as the first line will filter any nulls. However there are versions of SQL where this is not the case and retaining it in the query still works, hence I have left it in.

SQL: Is there a way for me to call another table.field when my initial table.field = NULL?

Morning All! Essentially, I found out that a potential table.field I'd like to use may not have the information I want, so, I might have to look into a separate field. My below thought process is:
If table.field1 = NULL then pull the value from table.field2. If table.field2 = NULL then state "No Phone"
My current SQL statement in the select, cause it's in a certain format, is:
substring(view_episode_summary_current.patient_home_phone, 1, 3) || ' ' || substring(view_episode_summary_current.patient_home_phone, 5, 8)
Above is let's say table.field1. I'm assuming I'll need to create a CASE statement right? I just didn't know how long it could be?
(case when view_episode_summary_current.patient_home_phone = NULL then table.field2)
But I don't know how to get it to evaluate if table.field2 = null and display the value.
In many databases, you can use coalesce() to implement that kind of logic:
coalesce(t1.field1, t2.field2) as myfield
coalesce() returns the first non-null value across its arguments. So it gives you t1.field1 if it is not null, else it falls back on t2.field2. If both are null, you get a null value as a result.
You could also use a case expression - there is no benefit as compared to colaesce(), but this can handle more complex cases than just nullity checks
case
when t1.field1 is not null then t1.field1
when t2.field2 is not null then t2.field2
end as myfield
case stops on the first branch where the condition is fulfilled. If no branch matches, it returns null - you can put an else branch at the end of your code to return something else.
Note that both techniques requires both fields to have similar data types.
You do not show your actual query so I cannot show how to use that in your code.

SQL Error (4145): An expression of non-boolean type specified in a context where condition is expected, near '('

Using the below statement to check whether a field is null and if it is null then I need to show "Not Yet Approved" message. Otherwise I would like to get a concatenated result of some fields which is mentioned below.
select
iif(isnull(AppByENo1,'true'),'Not Yet Approved',AppByENo1+AppByDesg1+AppByDate1) as result
from myDB
where (E_No = '25')
But getting the above mentioned error while trying to run the sql query.
Please advice where I am making mistake and how to tackle this issue.
try this:
select
iif(isnull(AppByENo1,'true') = 'true','Not Yet Approved',AppByENo1+AppByDesg1+AppByDate1) as result
from myDB
where (E_No = '25')
Use CASE Statement in SELECT clause instead of IFF :
SELECT CASE WHEN ISNULL(AppByENo1,'true') = 'true' THEN 'Not Yet Approved'
ELSE AppByENo1+AppByDesg1+AppByDate1 END as result
FROM myDB WHERE E_No = '25'
Since concatenating null values yields null (providing you're leaving appropiate settings turned on, which you should), you can just use a simple coalesce to replace the null if necessary:
select
COALESCE(AppByENo1+AppByDesg1+AppByDate1,'Not Yet Approved') as result
from myDB
where (E_No = '25')
If you insist on the iif approach, I'd favour:
iif(AppByENo1 is null,'Not Yet Approved',AppByENo1+AppByDesg1+AppByDate1)
E.g. an actual null test, rather than trying to identify a sentinel string that cannot appear naturally and performing a string comparison after isnull.

Sql Server: CASE Statement does unexpected behavior when comparing to NULL

Given:
The following Select statement:
select case NULL
when NULL then 0
else 1
end
Problem:
I'm expecting this to return 0 but instead it returns 1. What gives?
Generally speaking, NULL is not something you should attempt to compare for equality, which is what a case statement does. You can use "Is NULL" to test for it. There is no expectation that NULL != NULL or that NULL = NULL. It's an indeterminate, undefined value, not a hard constant.
-- To encompass questions in the comments --
If you need to retrieve a value when you may encounter a NULL column, try this instead:
Case
When SomeColumn IS NULL
Then 0
Else 1
End
I believe that should work. As far as your original post is concerned:
Select Case NULL
When NULL then 0 // Checks for NULL = NULL
else 1 // NULL = NULL is not true (technically, undefined), else happens
end
The trouble is that your Case select automatically attempts to use equality operations. That simply doesn't work with NULL.
I was going to add this as a comment to Aaron's answer, but it was getting too long, so I'll add it as another (part of the) answer.
The CASE statement actually has two distinct modes, simple and searched.
From BOL:
The CASE expression has two formats:
The simple CASE expression compares an expression to a set of simple expressions to determine the result.
The searched CASE expression evaluates a set of Boolean expressions to determine the result.
When the simple CASE (your example) does what it describes as comparison it does an equality comparison - i.e. =
This is clarified in the later documentation:
The simple CASE expression operates by comparing the first expression
to the expression in each WHEN clause for equivalency. If these
expressions are equivalent, the expression in the THEN clause will be
returned.
Allows only an equality check.
Because anything = NULL is always false in ANSI SQL (and if you didn't know this, you need to read up on NULLs in SQL more generally, particularly also with the behavior in the other searched comparison - WHERE x IN (a, b, c)), you cannot use NULL in a simple case and have it ever be compared to a value, with a NULL either in the initial expression or in the list of expressions to be compared against.
If you want to check for NULL, you will have to use an IF/ELSE construct or the searched CASE with a full expression.
I agree that it's kind of unfortunate there is no version which supports an IS comparison to make it easier to write:
select case colname
when IS NULL then 0
else 1
end
Which would make writing certain long CASE statements easier:
select case colname
when IS NULL then ''
when 1 then 'a'
when 2 then 'b'
when 3 then 'c'
when 4 then 'd'
else 'z'
end
But that's just wishful thinking...
An option is to use ISNULL or COALESCE:
select case COALESCE(colname, 999999) -- 999999 is some value never used
when 999999 then ''
when 1 then 'a'
when 2 then 'b'
when 3 then 'c'
when 4 then 'd'
else 'z'
end
But it isn't always a great option.
In addition to the other answers, you need to change the syntax for CASE slightly to do this:
SELECT CASE
WHEN NULL IS NULL THEN 0
ELSE 1
END;
Using the value in your syntax implicitly uses an equals comparison. NULL is unknown, and so is NULL = NULL, so with your current code you will always get zero 1 (geez I did it too).
To get the behavior you want, you can use SET ANSI_NULLS ON; however note that this can change other code in ways you may not be able to predict, and the setting is deprecated - so it will stop working at all in a future version of SQL Server (see this SQL Server 2008 doc).
You need to use the IS NULL operator. Standard comparison operators do not work with NULL.
Check out these MSDN articles about Null that may be useful:
IS [NOT] NULL (Transact-SQL)
Null Values

Regex: does a SQL statement include a WHERE clause?

I need a regex that will determine if a given SQL statement has a WHERE clause. My problem is that the passed SQL statements will most likely be complex, so I can not rely on just the existence of the word WHERE in the statement.
For example this should match
SELECT Contacts.ID
, CASE WHEN (Contacts.Firstname IS NULL) THEN ''
ELSE CAST(Contacts.Firstname AS varchar)
END AS Firstname
, CASE WHEN (Contacts.Lastname IS NULL) THEN ''
ELSE CAST(Contacts.Lastname AS varchar)
END AS Lastname
, CASE WHEN (tbl_ContactExtras.Prequalified=-1 OR
tbl_ContactExtras.Prequalified IS NULL) THEN ''
WHEN tbl_ContactExtras.Prequalified=0 THEN 'No'
WHEN tbl_ContactExtras.Prequalified=1 THEN 'Yes - Other'
WHEN tbl_ContactExtras.Prequalified=2 THEN 'Yes'
ELSE CAST(tbl_ContactExtras.Prequalified AS varchar)
END AS Prequalified
FROM contacts
LEFT JOIN tbl_ContactExtras
ON tbl_ContactExtras.ContactID = Contacts.ID
WHERE (Contacts.Firstname LIKE 'Bob%')
and this should not match:
SELECT Contacts.ID
, CASE WHEN (Contacts.Firstname IS NULL) THEN ''
ELSE CAST(Contacts.Firstname AS varchar)
END AS Firstname
, CASE WHEN (Contacts.Lastname IS NULL) THEN ''
ELSE CAST(Contacts.Lastname AS varchar)
END AS Lastname
, CASE WHEN (tbl_ContactExtras.Prequalified=-1 OR
tbl_ContactExtras.Prequalified IS NULL) THEN ''
WHEN tbl_ContactExtras.Prequalified=0 THEN 'No'
WHEN tbl_ContactExtras.Prequalified=1 THEN 'Yes - Other'
WHEN tbl_ContactExtras.Prequalified=2 THEN 'Yes'
ELSE CAST(tbl_ContactExtras.Prequalified AS varchar)
END AS Prequalified
FROM contacts
LEFT JOIN tbl_ContactExtras
ON tbl_ContactExtras.ContactID = Contacts.ID
Those are examples of some of the simpler statements: a statement could have up to 30 CASE statements in it, or it could have none at all.
I need to programmatically add WHERE parameters, but doing this correctly requires knowing whether a WHERE clause is already present.
Any idea on a regex that would work for this? If not, any other ideas on how to tell the two apart?
Thanks,
This is not possible, since a WHERE clause may be arbitrarily nested inside the FROM clause.
This may not catch all cases but you may find you can catch most of them just by finding the last from and the last where in the statement.
if the where is after the from, then it has a where clause. If the where is before the from (or there is no where at all), then no where clause exists.
Sometimes, it's okay to leave restrictions or limitations in your code, as long as they're properly documented.
For example, I've worked on a project before that parsed SQL and we discovered it didn't handle things like between:
where recdate between '2010-01-01' and '2010-12-31'
Rather than spend a bucket-load of money fixing the problem (and probably introducing bugs on the way), we simply published it as a restriction and told everyone they had to change it to:
where recdate >= '2010-01-01'
and recdate <= '2010-12-31'
Problem solved. While it's good to keep customers happy, you don't have to cater to every whim :-)
Other than that, you need an SQL parser, and SQL is not a pretty language to parse, trust me on that one.
Are all of the joins the same? If so you could find the index of all or part of the FROM statement (perhaps using a regex to be tolerant of slight differences in syntax and whitespace) and then look for the occurrence of the word WHERE after that index.
In general you would be better off using a parser. But if this is just a one off thing and the statements are all fairly similar then the above approach should be okay.
Regex is not designed to do this. Parsing SQL properly requires matching balanced parentheses (and other matching pairs, such as quotes), something regex is not designed to do (and pure regex isn't even equipped to; PCRE can but it's not pretty).
Instead, just write a basic state machine or something to parse it.
What's the problem you're trying to solve? Are you trying to determine if it's safe to add constraints to these existing queries?
For example, if you've got this query
...
where foo = 'bar'
then you know it's safe to add
and bat = 'quux'
but if you don't have a WHERE clause already, then you have to do it as
where bat = 'quux'
Is that the problem you're trying to solve? If so, can you make every SQL query you're working with have a WHERE clause by adding a "WHERE 0=0" to those queries that don't have one? Then you know in your post-process phase that every query already has one.
This is just a guess, of course. Your question sounded like that might be the larger issue.