SQL Sever: in...case...in WHERE clause - tsql

I need to code up a query for something like this:
Select [something]
Where
condition in
case
when (if another_condition = A and 3rd Condition = B) then (C,D)
when (if another_condition = N and 3rd Condition = E) then (F,G)
else (J,K)
end
essentially, what I want is if A and B are met, condition could be set to either C or D, if N or E are met, then condition could be set to F or G, else condition set to J or K.
However, when I run this, I kept getting
Incorrect syntax near the keyword 'Case'.
Please help! Thanks!

Maybe this:
Where (Another_Condition = 'A' And Third_Condition = 'B' And Condition in ('C','D'))
Or
(Another_Condition = 'N' and Third_Condition = 'E' And Condition in ('F','G'))
Or
Condition In ('J','K')
Be very careful about mixing and's and or's in a where clause. Parenthesis are important.

How about this - the UNION subquery will give you the full result set within the subquery. Then you can say 'WHERE condition IN ' (subquery). Like this:
SELECT [something]
WHERE
condition IN
(SELECT CASE WHEN (another_condition = A AND 3rd Condition = B) THEN C
WHEN (another_condition = N AND 3rd Condition = E) THEN F
ELSE J
END AS Value
UNION
SELECT CASE WHEN (another_condition = A AND 3rd Condition = B) THEN D
WHEN (another_condition = N AND 3rd Condition = E) THEN G
ELSE K
END AS Value
)

I'd probably go with G Mastro's approach of expanding the query as a Boolean expression. While the nested query approach will work, the intent of the code is less obvious IMO.
Having said that, if there are a lot of cases in your CASE statement, you may want to consider reshaping your data, because no matter how you write the query, it boils down to a big Boolean expression.

Related

T-SQL Nested Case Statement - Else Continue Nesting Case

In SQL Server, is there a way for nested case statements to ELSE continue the nesting CASE statement?
CASE
WHEN ... then
CASE
WHEN ... THEN
ELSE **[Continue to below WHEN]** END
WHEN ... then
WHEN ... then
ELSE ... END
Wondering if I can keep the code clean by not copy/pasting the proceeding WHEN statements into the nested CASE.
Flatten the nesting. So instead of this:
CASE
WHEN A then
CASE
WHEN B THEN C
WHEN D THEN E
ELSE **[Continue to below WHEN]** END
WHEN F then G
WHEN H then I
ELSE J END
You have this:
CASE
WHEN A AND B THEN C
WHEN A AND D THEN E
WHEN F then G
WHEN H then I
ELSE J END
A CASE expression (not statement: CASE cannot branch among SQL segments, only return a value) will stop at the first match, so by flattening the nesting and using and AND to tie in the nested conditions you will get the desired behavior.

How to skip a loop in kdb?

I have the following
mydata:raze {[x]
L: select from ....
if[count[L] <= 20; continue]
} peach vals;
and I am trying to add an if-statement that would skip a particular entry in vals if the condition is not met. continueworks well in matlab, but, I am not sure of the corresponding syntax in kdb. Thank you.
You can use an explicit return (:) in the if statement to return an empty list for those cases. Something like:
mydata:raze {[x]
L: select from ....
if[count[L] <= 20; :()]
} peach vals;

How to use 'if' 'else' statements in hiveql?

I am not sure if we can use if else in Hiveql or not. So wanted to know how we can write if else statements in hiveql
You can use IF (Returns valueTrue when testCondition is true, returns valueFalseOrNull otherwise):
if(boolean testCondition, T valueTrue, T valueFalseOrNull)
Or CASE (When a = true, returns b; when c = true, returns d; else returns e):
CASE WHEN a THEN b WHEN c THEN d ELSE e END
Or any other supported conditional function.

How do I use the Case Expression in conjunction with a where clause to divide one filed by another?

I am trying to figure out how to use case expression with a select query and a where clause and alias result as 'CaseOnOrder'.
Ideally when salunitmsr. = w then divide by U_SpecWgt as Case on order, when salunitmsr. = E than CaseOnOrder = OnOrder
I have two values that can only equal E or W, When the value is 'W' I would like the field OnOrder to divide by the U_SpecWgt field. When the Value is 'E' than the OnOrder qty will not need to be changed. The two select queries are below. I am not sure how to incorporate the case logic to divide when W is present, and keep the value the same when 'E' is present.
SELECT [ItemCode]
,[ItemName]
,[FrgnName]
,[ItmsGrpCod]
,[OnOrder]
,[U_SpecWgt]
FROM [xxxxx].[xxxxx].[xxxxx]
where
SalUnitMsr = 'e'
AND SellItem = 'Y'
and OnOrder > 0
SELECT [ItemCode]
,[ItemName]
,[FrgnName]
,[ItmsGrpCod]
,[OnOrder]
,[U_SpecWgt]
FROM [xxxxx].[xxxxx].[xxxxx]
where
SalUnitMsr = 'w'
AND SellItem = 'Y'
and OnOrder > 0
The query will include an aliased column that divides OnOrder by U_SpecWGT when salunitmsr = W, as cases on order, when E OnOrder = Cases on order.
SELECT
[ItemCode],
[ItemName],
[FrgnName],
[ItmsGrpCod],
CASE WHEN SalUnitMsr = 'W' THEN OnOrder/U_SpecWgt
WHEN SalUnitMsr = 'E' THEN OnOrder
END AS [CasesOnOrder],
[U_SpecWgt]
FROM [xxxxx].[xxxxx].[xxxxx]
where SalUnitMsr IN ('W','E') AND SellItem = 'Y' and OnOrder > 0

Cypher Neo4J - CASE Expression with MERGE

I'm trying to implement the logic in Cypher where, based on a particular condition (CASE Statement), I would create some nodes and relationships; the code is as below
MATCH (g:Game)-[:PLAYER]->(u:User)-[r1:AT]->(b1:Block)-[:NEXT]->(b2:Block)
WHERE g.game_id='G222' and u.email_id = 'xyz#example.com' and b1.block_id='16'
SET r1.status='Skipped', r1.enddate=20141225
WITH u, b2,b1, g, r1
SET b1.test = CASE b2.fork
WHEN 'y' THEN
MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2 {fork:'fail'}) RETURN 1
ELSE
MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2) RETURN 2
END
WITH u, g
MATCH (u)-[:TIME]->(h:Time)<-[:TIME]-(g)
SET h.after = 0
SET h.before = h.before + 1
In this query there is a merge statement within the WHEN 'y' THEN, this query throws an error:
Invalid input ']': expected whitespace or a relationship pattern (line 7, column 82)
"MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2 {fork:'fail'}) RETURN 1"
Basically I'm trying to create a relationship based on a property i.e. a MERGE within a CASE statement, I tried different ways to get this working like doing a return so that case when returns some value etc. but nothing worked so far.
What could be the issue with this query?
To do conditional write operations you need to use the FOREACH trick. Using CASE you either return a one element array or a empty one. FOREACH iterates over the CASE expression and therefore conditionally executes the action. If you want an ELSE part as well you need to have a another FOREACH using the inverse condition in the CASE. As an example, instead of
WHEN 'y' THEN
MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2 {fork:'fail'}) RETURN 1
ELSE
MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2) RETURN 2
END
use
FOREACH(ignoreMe IN CASE WHEN 'y' THEN [1] ELSE [] END |
MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2 {fork:'fail'})
)
FOREACH(ignoreMe IN CASE WHEN NOT 'y' THEN [1] ELSE [] END |
MERGE (u)-[r2:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2)
)
See also Mark's blog post on this.
Fixed the issue as below
WITH u, b2,b1, g, r1, CASE WHEN (b1.fork='y' and b2.fork='success') or (b1.fork='n') or (b1.fork='success') THEN ['ok'] ELSE [] END as array1
FOREACH (el1 in array1 | MERGE (u)-[r2:STAGE {startdate:20141225, enddate:99999999, status:'InProgress'}]->(b2))
i.e. used CASE WHEN to create a dummy array that in a way has dummy elements matching the count of matches and then use FOREACH to iterate through the result.
Again, thanks Stefan for the idea...
Deepesh
The APOC plugin supports Conditional Cypher Execution, which now allows us to avoid the FOREACH workaround.
For example, you can do this:
MATCH (g:Game)-[:PLAYER]->(u:User)-[r1:AT]->(b1:Block)-[:NEXT]->(b2:Block)
WHERE g.game_id='G222' AND u.email_id = 'xyz#example.com' AND b1.block_id='16'
SET r1.status='Skipped', r1.enddate=20141225
WITH u, b2, g
CALL apoc.do.when(
b2.fork = 'y',
"MERGE (u)-[:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2 {fork:'fail'})",
"MERGE (u)-[:STAGE {startdate:20141225, enddate:'99999999', status:'InProgress'}]->(b2)",
{u: u, b2: b2}) YIELD value
WITH u, g
MATCH (u)-[:TIME]->(h:Time)<-[:TIME]-(g)
SET h.after = 0
SET h.before = h.before + 1
Although this answer does help me, I found the syntax very hard to understand. So that's why I wrote my own answer. Here I read a tsv file and generate multiple types of edges.
LOAD CSV WITH HEADERS FROM 'file:///data.tsv' AS r FIELDTERMINATOR '\t'
WITH r.movie_id as movie_id, r.person_id as person_id, r.category as category
MATCH (p:Person {person_id:person_id})
MATCH (m:Movie {movie_id:movie_id})
FOREACH (_ IN CASE WHEN category='actress' THEN [1] ELSE [] END |
MERGE (p)-[:ACTRESS {}]->(m)
)
FOREACH (_ IN CASE WHEN category='director' THEN [1] ELSE [] END |
MERGE (p)-[:DIRECTOR {}]->(m)
)
FOREACH (_ IN CASE WHEN category='cinematographer' THEN [1] ELSE [] END |
MERGE (p)-[:CINEMATOGRAPHER {}]->(m)
)
FOREACH (_ IN CASE WHEN category='actor' THEN [1] ELSE [] END |
MERGE (p)-[:ACTOR {}]->(m)
)
Here _ is some variable which is simply not used anywhere but a necessity for the syntax of cypher