SQL case when behaves like if else if - sql

When I write an sql case when statement(s), does it function like an if, if ,..if logic or if, else-if , else-if, else logic?
i.e if the condition matches case #1, will it still evaluate the other cases?

Any self-respecting database will short circuit, but you didn't mention which database you are using. So, try it: select case when 1=1 then 1 else 1/0 end and see.

The case statement evaluates the when conditions in order. It stops at the first condition that evaluates to true. This is ANSI standard behavior and, as far as I know, all databases support the case statement in this way.

Related

How to implement nested CASE statements in a SQL Select of a stored procedure?

I have a SELECT statement from a temp table in a stored procedure that selects these two columns:
DECLARE #Mode INT
CASE
WHEN t.Descr = '-- Prior Balance --'
THEN ''
ELSE t.ChgAmount
END AS ChgAmount,
CASE
WHEN t.Descr = '-- Prior Balance --'
THEN ''
ELSE t.PayAmount
END AS PayAmount,
I want to conditionally return those two columns differently depending on the value of #Mode, specifically if it is equal to 7.
I'm getting confused about the levels of nesting that I need and the formatting of doing this.
So far I have tried something like this:
CASE
WHEN #Mode = 7
THEN
CASE
WHEN t.TranDate > #Due
THEN t.ChgAmount
END
END AS CurrentCharges,
CASE
WHEN t.Descr = '-- Prior Balance --'
THEN ''
ELSE t.ChgAmount
END AS ChgAmount,
CASE
WHEN t.Descr = '-- Prior Balance --'
THEN ''
ELSE t.PayAmount
END AS PayAmount,
The above SELECT might work, but it would stil return the extra column. How should I nest the other, original, CASE statement for the ChgAmount?
First, let's clarify in abstract terms that in the following pseudo-code
If X then
Case 1
If Y then
Case 2
Else
Case 3
End If
Else
Case 4
End If
Case 1 is equivalent to "X is true"
Case 2 is equivalent to "X is true and Y is true"
Case 3 is equivalent to "X is true and Y is false"
Case 4 is equivalent to "X is false"
Furthermore, let's clarify that case-when criterias are logically very similar to our pseudo-code presented above of if-then, hence, you can apply composite criteria instead of nesting case-when if you prefer that, but also, you can implement nested case-when criterias, it's a matter of style.
As a result, you will need to formulate the logic you want to apply, by asking yourself the following questions:
do I need the same number of fields in my different cases? (if not, then you will probably need to write different queries in different cases)
what cases do I have for my fields if #Mode is 7?
what cases do I have for my fields if #Mode is not 7?
how can I merge my criterias in the points above into coherent (composite) criterias that would not require nesting?
If you answer these questions as an edit to this question, then we will be able to more properly answer your questions than the general terms I'm using in this answer and we may provide code for you as well. However, if you think this through, then you might also be able to implement this in a not nested way. And, if you are able to understand this as far as to implement it into a not nested way, then you could transform that implementation into a nested implementation as well.

Can i use break or exit in Case Statement?

SELECT CASE
WHEN vGlTransType = 'R' THEN tkt_seq_num
WHEN vGlTransType in ('A','E','X') then
break
END
there is no loop in CASE
use
ELSE null
before END to return a null value when other conditions are not satisfied
Like alex mentioned, you want ELSE:
SELECT CASE WHEN vGlTransType = 'R' THEN tkt_seq_num
ELSE NULL
END
ELSE NULL is default btw, that means you could just skip it:
SELECT CASE WHEN vGlTransType = 'R' THEN tkt_seq_num
END
You got a lot of negative responses because you use the wrong vocabulary. Let me quote a article I wrote on CASE:
SQL is a declarative language: it does not provide control over
program flow like if does for imperative programs. Nevertheless, SQL
has something similar: the case expression. Being an expression—rather
than a control structure—means that case varies the result of formulas
(expressions) based on conditions. Its use is similar to the ternary
operator ?: in other programming languages.
Your question suggest that you think SQL's CASE is similar to C's SWITCH (plus CASE). But it isn't.

Condition that decides whether to execute WHERE or not

I have a really big stored procedure and I'd like to include a WHERE clause at the end to be executed just in case that #myparameter=1. I don't want the stored procedure to pay any attention to the WHERE clause when #myparameter=0. Is there any way to do this with CASE or something like that?
WHERE #myparameter=0 OR (insert the current conditions here)
add a modified version of where instead of yours
where (#myparemeter = 0 or (#myparameter = 1 and (your where conditions here)))
If you really want to use CASE, something like this ...
WHERE
CASE
WHEN (#myparameter=0) THEN 1
WHEN (#myparameter=1) AND (rest of where clause) THEN 1
ELSE 0
END = 1

SQL CASE in Query - Odd behavior

Using a Case Statement in a query seems to work fine as long as the only case you want to match to is a string. But if you want to put ">" greater than (date or number), etc, SSMS automatically adds apostrophes around your statement (below) as if it were a string.
How can I get it to accept "greater than date" or "greater than number", etc??
There are two types of CASE expression:
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.
You want a searched CASE expression. This means that the WHEN should come immediately after the CASE keyword.
CASE WHEN SoldDate <= SubjectDate THEN ...
There are two types of CASE expressions (from msdn):
A Simple CASE compares the specified expression for EQUIVALENCY ONLY
SELECT FieldName CASE WHEN 'Blah' THEN 'Foo' ELSE 'Bah' END
A Searched CASE can do inequalities too but has more verbose syntax:
SELECT CASE WHEN FieldName >= 'Blah' THEN 'Foo' ELSE 'Bah' END
You are trying to use the Simple syntax and need to use the Searched syntax by explicitly writing out the fieldname and comparison for each evaluation.
Your CASE statement syntax is incorrect. WHEN should come directly after CASE
This:
CASE SoldDate WHEN ...
Should be this:
CASE WHEN SoldDate <= SubjectDate THEN SoldFor ELSE EstSalePrice END
Additional Information
Take a look at the MSDN docs for additional examples of CASE syntax.

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.