What does this SQL WHERE clause mean? - sql-server

I'm having some difficulty in understanding the following WHERE clause in a T-SQL (SQL Server 2000/2005) query:
update #tempTable
SET
Total_Avg=isnull(TerminationReason,'terminated'),
Individual_Subscriptions=null,
Business_Subscriptions=null,
Other_subscriptions=null,
-- snip. 10 more fields set to NULL.
PMIE_BI=null,
Digital_Editions_BI=null
where
(
AbcTerminationDate<=dbo.fnGetPeriodFinalDate(#periodid)
and (AbcTerminationDate!=19000101 or AbcTerminationDate is null)
and (Total_Avg is not NULL or PrevTotalAvg is not NULL)
)
Specifically, the second clause doesn't make sense to me - it's 2 sub-clauses separated by the OR operator seem contradictory.
The AbcTerminationDate field is declared as INT NULL in a table called Members. I believe a date of 19000101 in the system means NULL or a default value or no value, i.e. that a member is NOT terminated. So the query appears to blank out a whole lot of fields/figures if a member is marked as terminated, which would be when the AbcTerminationDate is NULL or has the default value.
Without knowing any more information, what do you make of it?

It does look like those are contradictory. Perhaps they meant
and !(AbcTerminationDate==19000101 or AbcTerminationDate is null)
?

Whatever 19000101 is "supposed" to mean, it is not the same as NULL in the eyes of the database. NULL is NULL. If you try to evaluate any other value to NULL then it can become problematic, because NULL means "unknown". For example, does 1=NULL? Maybe it does, maybe it doesn't. In fact, you can't even say that NULL=NULL, because each NULL is unknown so might or might not be equal to the other. It's safest to explicitly check for NULL conditions.
EDIT:
As I point out in my comment, if NULLs are to be included then the first part of the query precludes that. Here is how it should be written if NULLs should be included:
(
(
(
AbcTerminationDate <= dbo.fnGetPeriodFinalDate(#periodid) AND
AbcTerminationDate != 19000101
) OR
AbcTerminationDate is NULL
) AND
(Total_Avg is not NULL or PrevTotalAvg is not NULL)
)

If the "or" arg were outside the () grouping it would negate:
AbcTerminationDate<=dbo.fnGetPeriodFinalDate(#periodid)
[edit]
Basically it's saying to take whatever results are true from that 1st clause, and perform an additional filter to make sure it's not 19000101 or it's null, are most likely exceptional values for the fnGetPeriodFinalDate function to properly evaluate.

Related

Wrapping ISNULL around NULLIF

Suppose that I have:
case
when #ID ='2386002' then ISNULL(nullif(i.call,''),i.standingOrderNumber)
when nullif(rtrim(i.call),'') is null then
nullif(rtrim(i.standingOrderNumber), '')
else case when nullif(rtrim(i.standingOrderNumber),'') is null then rtrim(i.call)
else
rtrim(i.call)
This is just a part of the procedure which does synchronization between two apps, the problem is that standingOrderNumber is not synchronized and I assume it has to to do with this code portion.
Scenario:
After entering call and standingOrderNumber like this:
call: '' (leave it empty)
standingOrderNumber: 777777
Data is stored in a table and procedure takes the data from that table and displays it on the app form, problem is, everything is displayed correctly, except for this standingOrderNumber.
Can you tell if something went wrong in the logic I submitted above ?
I think problem with the below line,
when #ID ='2386002' then ISNULL(nullif(i.call,''),i.standingOrderNumber)
here you are trying to check i.call for null value and replacing it with empty string and that makes ISNULL function useless.
Solution is not to use nullif in above line

How to use If Else Condition in Where Clause in SQL Server for Date Columns?

I want to use if else in where condition for Date Coulmns. Actually what i want to do is:
I have a table, which having two columns, CreatedDate and LastModifiedDate. Now what i want to check in Stored Proc is:
if LastUpdateDate is null then it will check for CreatedDate.
Below is my query:
SELECT isnull(SSA.UpdateDateTime,
isnull(SSA.CreateDateTime,'')) as LastUpdateAnswerDateTime
from SI_SurveySiteAnswer SSA
WHERE SSA.UpdateDateTime IS NOT NULL
There are other number of table in joins i am just pasting the required query only. how can i go for the check i am totally confused.
Please help me..
UPDATED:
I have write the below code, please confirm if it is the correct way to use If in where
SELECT isnull(SSA.UpdateDateTime,
isnull(SSA.CreateDateTime,'')) as LastUpdateAnswerDateTime
from SI_SurveySiteAnswer SSA
WHERE SSA.UpdateDateTime = ISNULL(SSA.UpdateDateTime,SSA.CreateDateTime)
I think i was not able to make my requirement very clear in first go, let me explain here..
i have a survey question answer table, i want to send an email notification if question has been answered, now answer can answered in one go, in that case createddate will have value not the updateddatetime,
Second case is:
answer is being updated in second go, then i need to check for the LastUpdateDateTime..
That's what i want to make in query.
You don't need any if / else functionality, just use the or operator to check that either is not null:
WHERE SSA.CreateDateTime is not null OR SSA.UpdateDateTime is not null
You can use COALESCE if you want this functionality, here are some sites for your reference.
http://www.mssqltips.com/sqlservertip/1521/the-many-uses-of-coalesce-in-sql-server/
http://sqlmag.com/t-sql/coalesce-vs-isnull
you can use case
SELECT Isnull(SSA.updatedatetime, Isnull(SSA.createdatetime, '')) AS
LastUpdateAnswerDateTime
FROM si_surveysiteanswer SSA
WHERE SSA.updatedatetime = CASE
WHEN SSA.updatedatetime IS NULL THEN
#SSA.createdatetime
ELSE SSA.updatedatetime
END
Try case statement.
SELECT isnull(SSA.UpdateDateTime,
isnull(SSA.CreateDateTime,'')) as LastUpdateAnswerDateTime
from SI_SurveySiteAnswer SSA
WHERE CASE WHEN SSA.UpdateDateTime IS NULL THEN SSA.CreateDateTime
ELSE SSA.UpdateDateTime END IS NOT NULL

T-SQL: What is NOT(1=NULL)?

I don't get the simple boolean algebra on my sql-server. According to msdn, the following statement should return "1", but on my server it returns "0".
Can you help me?
SET ANSI_NULLS ON
SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END
Please have a look at msdn. There it clearly states: "Comparing NULL to a non-NULL value always results in FALSE." - no matter what the ANSI_NULLS-setting is. Thus "1=NULL" should be FALSE and NOT(FALSE) should thus be TRUE and the statement should return "1".
But on my machine, it returns "0"!
One explanation might be, that "1=NULL" evaluates to "UNKNOWN". NOT(UNKNOWN) is still UNKNOWN (msdn), which would force the CASE-Statement into the ELSE.
But then the official documentation of the equals-operator would be wrong. I cannot believe this!
Can anybody explain this behaviour?
Thank you very much for any help!
Edit (2012-03-15):
One thing I just found that might be of interest for some of you:
CREATE TABLE #FooTest (Value INT)
ALTER TABLE #FooTest WITH CHECK ADD CONSTRAINT ccFooTestValue CHECK (Value>1)
PRINT '(NULL>1) = ' + CASE WHEN NULL>1 THEN 'True' ELSE 'False' END
INSERT INTO #FooTest (Value) VALUES (NULL)
The print-Statement writes 'False', but the insertion runs without error.
SQL-Server seems to negate the check-constraint in order to search for rows that do not fulfill the constraint-check:
IF EXISTS (SELECT * FROM inserted WHERE NOT(Value>NULL)) <Generate error>
Since the check-constraint evaluates to UNKNOWN, the negation is also UNKNOWN and SqlServer does not find any row violating the check-constraint.
Yes that link is wrong. File a documentation bug on Microsoft Connect.
Sql uses three valued logic not boolean logic. true, false, and unknown
Most comparison operators (i.e. excluding IS [NOT] NULL) involving NULL result in unknown not True or False. Negating unknown yields unknown as per the truth tables shown here.
The MSDN page for Equals that you link to definitely appears incorrect.
Check the MSDN page for SET ANSI_NULLS.
When SET ANSI_NULLS is ON, all comparisons against a null value
evaluate to UNKNOWN.
To get that example SQL statement to work as expected, you should use compare using "IS NULL" or "IS NOT NULL" instead of using the equals operator (=). For example:
SELECT CASE WHEN NOT(1 IS NULL) THEN 1 ELSE 0 END
OR
SELECT CASE WHEN (1 IS NOT NULL) THEN 1 ELSE 0 END
You want to read the documentation on ANSI_NULLS. SQL actually implements a ternary logic, not boolean logic, where a comparison operation can result in true, false or undefined. Basically, this means that the explanation you proffered is correct.
This can be demonstrated with the following query:
SET ANSI_NULLS ON
SELECT CASE
WHEN (1=NULL) THEN 0
WHEN NOT(1=NULL) THEN 1
ELSE -1
END
Which results in -1 on my machine (SQL Server 2005 Enterprise). Changing the first line to SET ANSI_NULLS OFF produces 1 as expected.
So, is the official documentation wrong? I'd submit that is somewhat misleading. It says that it results in FALSE. Obviously this is wrong. What the documentation meant to say is that comparing a non-null to NULL always results in a mismatch whose value also depends on ANSI_NULLS.
Of course, on SQL Server 2012, the ANSI_NULLS setting has been removed, and therefore setting it any which way will not change the result.
It's not boolean logic, its trinary logic: {True, False, I Don't Know.} Break it down this way:
IF 1=NULL
print 'True'
else
print 'False'
Generates False because 1=NULL equals NULL, aka "not True"
IF not(1=NULL)
print 'True'
else
print 'False'
Also generates False because not(1=NULL) equals not(NULL) equals NULL, aka "not True". This gets you to
SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END
which as per above is the same as
SELECT CASE WHEN NULL THEN 1 ELSE 0 END
which, since NULL is not true, resovles to the ELSE clause.
In short, as far as I'm concerned the documentation is incorrect. Distressing, but not unique, and so not entirely surprising.
Try using EXISTS in a subquery, it uses 2 valued logic and will give you the true/false you are looking for.
From BOL (credit to Thomas):
SET ANSI_NULLS ON affects a comparison only if one of the operands of
the comparison is either a variable that is NULL or a literal NULL. If
both sides of the comparison are columns or compound expressions, the
setting does not affect the comparison.
So I guess the NOT operation is checking 1=NULL which is unknown and because this is not a variable or literal NULL gets the ELSE part of your comparison as you hypothesised.
1=NULL seems to return FALSE only when ANSI_NULLS is OFF. Otherwise it's indeterminate. The msdn page probably needs to be edited to clarify that point.
SET ANSI_NULLS OFF
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns true
go
SET ANSI_NULLS ON
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
go

SqlCommand, passing something that could be null

I have a SQL command that I've been asked to modify, and I'm having some troubles with the fact that what I'm passing to the SQL can now be null. If I'm passing a value, I can rely on the columnName = #parameterName in the SQL, but with NULL, I can't pass null or DBNull and have it correctly resolve.
Here's the SQL pseudocode:
SELECT
Columns
FROM
ClientSetup
WHERE
Client_Code = #ClientCode AND
Package_Code = #PackageCode AND
Report_Code = #ReportCode
The problem is that now #ReportCode can validly be NULL. In my C# code where I set up the SqlCommand, I can put in:
cmd.Parameters.Add("#ReportCode", SqlDBType.VarChar, 5).Value = reportType;
//reportType is a string, which can be null
But, if reportType is null, I need to use Report_Code IS NULL in the SQL, rather than Report_Code = #reportCode.
The solution I've found is to change the last where clause to the following:
((#ReportCode IS NULL AND Report_Code IS NULL) OR Report_Code = #ReportCode)
and the parameter phrase to
cmd.Parameters.Add("#ReportCode", SqlDBType.VarChar, 5).Value = string.IsNullOrEmpty(reportType) ? System.DBNull : reportType;
What this does works, but I was wondering if anyone knew of a cleaner or better way to handle nullable parameters when passing things to SQL from .NET code.
The short answer is that no, the SqlClient API requires you to pass in a DbNull.Value for NULL parameter values.
But I have some doubts about how you treat NULLs. For one you use string.IsNullOrEmpty which means that you treat the emtpy string as a NULL. This is questionable, there may be legitimate empty string values in the database.
My second concern is the logic of matching NULLs in the database. More often than not passing in a NULL parameter means that the request is interested in any value, not specifically in NULL values. I'm not saying your logic of matching NULL parameters to NULL values is flawed, I just want to make sure you know what you're doing.
Much of a muchness, in the past I've built the query
test reportcode for null if is its replace ReportCode = #ReportCode with "ReportCode is Null"
add the reportcode parameter if it isn't.
Generally though ReportCode of null signalled I wanted to select based on the other parameters and didn't care what the null one was.
It's a bit naughty
but Where IsNull(ReportCode,'') = IsNull(#ReportCode,'')
would give you what you want, given you are using IsNullOrEmpty.
Well, is correct the way how you fix it
only is (#ReportCode IS NULL AND Report_Code IS NULL) not is neccesary. because it is not c# o c++.
Some how that should be finally result
SELECT
Columns
FROM
ClientSetup
WHERE
Client_Code = #ClientCode
AND Package_Code = #PackageCode
AND (Report_Code = #ReportCode or #ReportCode is null)

Filtering by ALL or by selected attribute

Excuse my language or SQL/Reporting wording
I am generating a report using Reporting Services where I have 2 drop down lists in order to show only by period and by category. I want it so if I select and I am shown all entries and if selected from any of the 2 drop downs then filter by those selections. I have a stored procedure which states the following on it's WHERE clause:
WHERE (dbo.PERIOD_LIST.PERIOD_DESC = #period) OR (dbo.CATEGORY.CATEGORY_DESC = #category)
However I cannot get this to work on Reporting Services/Visual Studio. I am shown ALL the entries instead of the filtered ones. I initialize #period and #category as NULL. So how can I make it so the report shows all rows when both attributes are null and still be able to filter by each or both of them?
How can I achieve this?
Edit: I used the suggestion Filip Popović gave me. If you're having this problem modify your prepared statement and make sure you refresh fields on your data sets since there's additional clauses on your prepared statement!
Note that in SQL, NULL = NULL is never evaluated to true. You can take it as NULL is not nothing it is something but unspecified. And You can't compare two unspecified values. You have to test COL1 IS NULL to get true if column has null value.
Try this:
WHERE ((dbo.PERIOD_LIST.PERIOD_DESC = #period) OR (#period IS NULL))
AND ((dbo.CATEGORY.CATEGORY_DESC = #category) OR (#category IS NULL))
Check the parameter for NULL as part of the condition:
WHERE ((#period IS NULL) OR (dbo.PERIOD_LIST.PERIOD_DESC = #period))
AND ((#category IS NULL) OR (dbo.CATEGORY.CATEGORY_DESC = #category))

Resources