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.
Related
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.
I am trying to understand why my code doesn't work! I am trying to solve the classic balance parentheses problem and Im getting a no such element on my third if statement which doesn't make sense to me because I thought my second if statement would avoid that case but I dont think my second if statement is returning?
def balance(chars: List[Char]): Boolean = {
def check(left: Int,right: List[Char]): Boolean = {
if (left < 0) false
if (right.isEmpty) left == 0
if (right.head == ')') check(left + 1, right.tail)
else check(left - 1, right.tail)
}
check(0,chars.filter(x => (x == ')') || (x == '(')))
}
Following up on my comment. I don't believe that you are actually getting a Null Pointer exception. Scala doesn't encourage the use of nulls and I don't know of any case where the standard library will return a null. Nulls are encapsulated by Option.None in Scala (or see upcoming explicit nulls in Scala 3) and even when you are integrating with a Java library, it is recommended that you wrap the null behavior in an option.
That being said, under the assumption that you are getting a No Such Element Exception in reality, let's look at you code.
Understanding the return behavior in Scala
A Scala function will take the last value in it's body as it's return value. In your case it is this block
if (right.head == ')') check(left + 1, right.tail)
else check(left - 1, right.tail)
Since the previous if blocks are not conditionally linked together all 3 of them will be evaluated. Even if one of the first two evaluates the true, Scala will NOT return and continue to evaluate because it sees more code in the function body it has not computed yet.
So in this case even if the second condition is true, the third one still gets evaluated.
Use the full ternary syntax and add else
if (left < 0) false else
if (right.isEmpty) left == 0 else
if (right.head == ')') check(left + 1, right.tail)
else check(left - 1, right.tail)
More on ternary syntax here
Let us desugar check definition a little bit:
def check(...) =
{
if (left < 0) false else (); // expression 1
if (right.isEmpty) left == 0 else (); // expression 2
return if (right.head == ')') check(...) else check(...); // expression 3 (last expression)
}
Note how the semicolons ; make it clear we have three separate expressions in the expression block, and only the last one is passed to return. Now the two key concepts to understand are
conditional expressions if (𝑒1) 𝑒2 else 𝑒3 are first-class values (and not control statements)
the "returned" value of the whole block expression is only the value of the last expression in the block
Hence to fix the issue, as suggested by others, we need to connect the three separate expressions into a single expression of the form if...else if ... else if ... else.
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
if (updateYN.ToUpper() != Constants.NO
|| updateYN.ToUpper() != Constants.N)
{
// execute code for any other updateYN
}
I am trying to perform a filtration that if the value of updateYN is not NO(Constants.NO) or N(Constants.N), then execute the statement.
But the problem is that, irrespective of the values, the if block is executing.
It seems like you want an AND statement...no? (NOT NO AND NOT N)
Logically think about it this way:
your statement breaks down into three components
a = updateYN.ToUpper() != Constants.NO
b = updateYN.ToUpper() != Constants.N
c = a or b
But if you think about it, if updateYN.ToUpper() is Constants.NO then a is false, but b is true, and thus c is true. And if updateYN.ToUpper() is Constants.N then b is false, but a is true, and thus c is true. What you seem to want is
if(updateYN.ToUpper() != Constants.NO && updateYN.ToUpper() != Constants.N)
This means that updateYN.ToUpper() must equal something other than Constants.NO and Constants.N in order for the entire statement to be true.
OK, your problem is you are translating language to code. Your statement should be:
if (updateYN.ToUpper() != Constants.NO
&& updateYN.ToUpper() != Constants.N)
{
// execute code for any other updateYN
}
This tells the compiler that updateYN.ToUpper() should not be NO and should not be N.
EDIT: To make it more clear why your if condition is always getting concluded, here is some explanation. Imagine this statement:
if (x != 1 || x != 2)
{
...
}
You would imagine that if x is 1 or 2, the block shouldn't be executed, but it WILL, because this statement consists of two parts actually:
x != 1
x != 2
The or part tells the compiler that if any of these conditions is true, then the whole condition is true. Obviously, if x is 1, then it is not 2, so the condition is fulfilled, and same thing if it is 2. Think of all the values in the world, they can't be equal to 1 and 2, so this block will always get executed. Same with your case here. Hope that explains your problem well.
If Constants.NO and Constants.N are not equal, this is always true. It is probably always different from either NO or N.
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.