How to convert or rewrite Access IIF Statement in SQL Server - sql-server

I thought the IIf statements returns one value if the condtion is true or false BUT This IIf statement in Access returns the field and it values.
IIf([A1]![KPr],[A1]![Kat],IIf([Data2]![Kat],[Data2]![Kat],[Data1]![Kat])),
the table left join in the from clause
I'm try to realize this statement in SQL Server using CASE WHEN but it also accepts a true or false condition.
How can I understand and realize this statement.

IIf function in VB, VBA, and Access is the same as ps_prakash02 wrote in the comment: iif(condition, value_if_true, value_if_false). this means that if the condition evaluates to true, the value_if_true is returned, otherwise value_if_false returns.
So a translation of IIf to t-sql is simply CASE WHEN condition THEN value_if_true ELSE _value_if_false END.
I'm not so sure what [A1]![KPr] means in access, I'm guessing it's KPr column value of table A1 or something like this, so I'll leave them as they are in your question and just replace the IIF with CASE in my answer:
CASE WHEN [A1]![KPr] THEN [A1]![Kat]
ELSE
CASE WHEN [Data2]![Kat] THEN [Data2]![Kat]
ELSE [Data1]![Kat]
END
END
Note: In SQL Server 2012 Microsoft included IIF in t-sql.

Related

Why does "= ALL (subquery)" evaluate to true if the subquery returnes no results?

I would expect "= ALL (subquery)" to evaluate to false if the subquery returns no results.
However in testing I find that not to be the case:
--put one record in #Orders
SELECT 1 AS 'OrderID'
INTO #Orders;
--put one record in #OrderLines
SELECT
1 AS 'OrderID'
,1 AS 'OrderLineID'
,3 AS 'Quantity'
INTO #OrderLines;
--as expected this returns the record in #Orders
SELECT *
FROM #Orders
WHERE 3 = ALL
(
SELECT Quantity
FROM #OrderLines
);
--now delete the record in #OrderLines
DELETE FROM #OrderLines;
--this still returns the record from #Orders even though the subquery returns no results
SELECT *
FROM #Orders
WHERE 3 = ALL
(
SELECT Quantity
FROM #OrderLines
);
Execution plan for the final select statement: https://www.brentozar.com/pastetheplan/?id=H1jQ2YgIK
Tested on:
Microsoft SQL Server 2017 (RTM-CU20) (KB4541283) - 14.0.3294.2 (X64)
Microsoft SQL Server 2017 (RTM-CU25) (KB5003830) - 14.0.3401.7 (X64)
When searching I find unofficial sources which say that "= ALL (subquery)" evaluates to true if the subquery returns no results:
"The ALL must be preceded by the comparison operators and evaluates to TRUE if the query returns no rows" https://dotnettutorials.net/lesson/all-operator-sql-server/
"The ALL must be preceded by the comparison operators and evaluates to TRUE if the query returns no rows" https://www.w3resource.com/sql/special-operators/sql_all.php
But I don't see anything in the official documentation (https://learn.microsoft.com/en-us/sql/t-sql/language-elements/all-transact-sql?view=sql-server-ver15) that supports that idea, in fact it would seem to dispute it: "ALL requires the scalar_expression to compare positively to every value that is returned by the subquery"
Questions
Is it expected behavior in SQL Server to evaluate ALL as true if the subquery returns no results?
If the answer to #1 is "yes":
Is it documented somewhere?
What is the explanation for that behavior? In the code example above 3 does not compare positively with no results so it seems highly unintuitive that the query should return results
Thanks for any assistance and insight.
Paraphrasing the documentation:
... scalar_expression = ALL (subquery) would evaluate as FALSE if some of the values of the subquery don't meet the criteria of the expression.
It's subtle, but the intention seems to be return false if some values do not satisfy the condition, true otherwise. In the edge case of there being no values, there are no values that don't satisfy the condition, so it returns true.
The "problem" causing the perhaps surprising result is the word "some", which implies existence. If no values exist, there can't be "some" values that are false, so it's true.
You could say it's based on double negative logic where the edge case happens to fall in the unexpected half of the result.
As a side note, I have written a huge amount of SQL in my career and never used this keyword, nor seen it used.
Recommendation: Do not use.

How to use ISNULL in SQL between clause

I have a SQL Server stored procedure that someone wrote where they are using isnull in the where clause in conjunction with the between keyword. They are using the following:
isnull(JobNumber, '') between #BeginJob and #EndJob
What will this comparison return if the JobNumber column is null? Thanks.
It will be translated as empty string, as ISNULL transforms the NULL values of param1 (column provided) into param2 value. So in your case you use the column values between x and y , but when null it will use ""
https://learn.microsoft.com/en-us/sql/t-sql/functions/isnull-transact-sql?view=sql-server-2017
This expression prevents the use of index on JobNumber, if such index exists. Remove isnull, the result will still be the same, but faster.
variable #BeginJob may be passed in any case with ''.Look like JobNumber column is null-able that's why in case of space get return all.
because no comparison in between two null values always get null.

Can this SQL CASE WHEN statement be made shorter?

Are there any features within Microsoft SQL Server TSQL that could shorten this CASE WHEN statement?
CASE
WHEN some_column IS NULL
THEN 0
ELSE 1
END
For SQL Server 2012 and later you can use IIF() statement.
SELECT IIF(some_column IS NULL , 0 , 1)
You could use what SQL Server documentation calls the "simple" case expression, instead of the "search" case expression that the syntax in the question uses.
case some_column when null then 0 else 1 end
Not a large difference, but it is shorter.

Does SQL Server short-circuit IF statements?

I am working on optimizing some heavily used stored procedures and ran across a scenario that raised a question that I couldn't find any answers for: when evaluating TSQL in a stored procedure, does SQL Server short-circuit the IF statement?
For example, assume a stored procedure has code similar to:
IF #condition1 = 1
OR EXISTS(SELECT 1 FROM table1 WHERE column1 = #value1)
...
In this scenario does SQL Server short-circuit the evaluation such that the EXISTS statement is never executed when the preceding clause evaluates to true?
If it never or only sometimes does, then we have some rewriting ahead of us.
Even if it appears to work, it should not be relied upon. The CASE statement is the only thing that the documentation states as being short-circuiting, but even that isn't (or at least wasn't) always the case (hee hee). Here is one bug that was fortunately fixed as of SQL Server 2012 (see the comments).
In addition to the rabbit hole (an interesting one, for sure) of links in comments from the comment posted by #Martin on the question, you should also check out this article:
Understanding T-SQL Expression Short-Circuiting
and the discussion forum related to that article.
The good news is that it seems to short-circuit. Here's a minimal example:
DECLARE #condition1 bit = 1
IF (#condition1 = 1) OR EXISTS(SELECT 1 FROM sys.objects)
PRINT 'True'
ELSE
PRINT 'False'
When #condition is set to 1, this is the execution plan: 0 rows scanned from sys.objects
when #condition is set to 0, it scanned the sys.objects table:
But there is no guarantee that this will be the case every time.

Assigning a variable conditionally inside a SELECT statement on SQL SERVER

I am attempting to write a SELECT statement on SQL Server that displays items based on a condition, which I provide in the subsequent WHERE clause.
Here is a simplified version of what I am attempting to write.
DECLARE #tmpvar varchar(5)
....
SELECT #tmpvar,
....
FROM some_table
WHERE
....
and #tmpvar =
CASE WHEN (some condition here)
THEN 'YES'
ELSE 'NO'
END
The code above executes successfully, but when I check the value of #tmpvar, it remains unassigned.
I'd like to know if there is a mistake in the syntax I am using. If so, what would be the correct way of assigning the variable inside the SELECT statement using the given condition? Prior apologies if this question is redundant.
You can't assign in the WHERE clause. You can in the SELECT clause:
DECLARE #tmpvar varchar(5)
....
SELECT #tmpvar =
CASE WHEN (some condition here)
THEN 'YES'
ELSE 'NO'
END,
....
FROM some_table
WHERE
....
But only if you're not also attempting data retrieval at the same time. Also, it's pretty poorly defined which row(s) will influence the result if there's more than 1 row in the result set, unless you have an ORDER BY clause:
If the SELECT statement returns more than one value, the variable is assigned the last value that is returned.
As you may have noticed, SQL uses = for assignment, comparison and introducing aliases. Which one is determined by the position that the = appears in. In the WHERE clause, = can only be comparison.

Resources