Oracle Case Statement Expression usage, and TRUE/FALSE usage - sql

According to the documentation
for the Case Statement:
The CASE statement evaluates a single expression and compares it against several potential values
It appears that I can put expressions in the case statement that evaluate to a number, such as A + B, but I can't put an expression that evaluates to a boolean such as A = B. I am forced to put the expression in the when clause. I would expect Oracle to treat TRUE and FALSE as 1 and 0 and apply the same rules to them.
Why is this not valid?
Boolean Expressions Do Not Execute
-- boolean expression in case statement compared to 1 and 0
select case a = b
when 1 then
'EQUAL'
else
'NOT EQUAL'
end as _RESULT
from dual;
--boolean expression in case statement compared to TRUE and FALSE
select case a = b
when TRUE then
'EQUAL'
else
'NOT EQUAL'
end as _RESULT
from dual;
Numeric Expressions Do Execute
--numeric expression in case statement compared to the number 3
select case a + b
when 3 then
'THREE'
else
'NOT THREE'
end as _RESULT
from dual;
Boolean Expressions in the When Clause Do Execute
select case
when a = b then
'EQUAL'
else
'NOT EQUAL'
end as _RESULT
from dual;

Related

Shorthand CASE with additional conditions

Up until today I held as true the notion that shorthand CASE doesn't accept additional conditions, as in
CASE evaluate_this
WHEN TRUE AND another_field ... THEN ...
would never work.
Today, as I was distractingly writing some code, I violated this rule just to realise that one CASE expression still worked as intended, the other didn't.
Assuming the following data:
id
boolean_one
boolean_two
field_one
field_two
1
TRUE
TRUE
NULL
'a'
2
TRUE
FALSE
2
'a'
3
FALSE
TRUE
8
NULL
4
FALSE
FALSE
NULL
NULL
The one that did not work looked like this:
CASE boolean_one
WHEN TRUE AND field_one IS NOT NULL THEN field_one * UNIFORM(1, 10, RANDOM())
ELSE field_one
END AS new_field_one
The idea is that in most circumstances the value for new_field_one should match field_one, the only exception being when boolean_one = TRUE AND field_one IS NOT NULL in which case it should be assigned the product of field_one and a random integer.
Below the desired and actual values for new_field_one based on the above
id
desired
actual
1
NULL
NULL
2
20
20
3
8
8
4
NULL
5
So it applies the randomisation also when boolean_one = FALSE AND field_one IS NULL.
Fixing the expression to
CASE
WHEN boolean_one = TRUE AND field_one IS NOT NULL THEN...
solves the issue. What I find more interesting, and confusing, is that the second expression still did what it was meant to do:
CASE boolean_two
WHEN TRUE AND field_two = 'b' THEN 'a'
WHEN TRUE AND field_two = 'a' THEN 'b'
ELSE field_two
END AS new_field_two
which in this case means that new_field_two = 'b' for the row with ID = 1, and all other remain equal to field_two.
So, this doesn't seem to be an issue of adding an extra condition to a shorthand CASE per se, I would guess it must have something to do specifically with the fact that the second condition is a NULL check. Am I on the right track?
With the shortcut syntax the "when expression" is evaluated as a whole and then that value is compared against the "case expression". It's not matching the value as true and then running an extra check
In fact your true and is essentially ignored because true and X is just equivalent to X in Boolean logic. The test then is whether boolean_one matches the non-null state of field_one. The second and fourth rows correspond to true = true and false = false which is when you're seeing the random result values.
You could certainly nest case if there were a real benefit to legibility:
case boolean_one
when true then
case field_one is not null ... end
else field_one
end
Shawnt00 answer is good,
I like to think of the two forms as
chained If expression
CASE
WHEN check1 THEN r1
WHEN check2 THEN r2
WHEN check3 THEN r3
END
if the same as
IF(check1)
r1
ELSE IF (check2)
r2
...
where-as this "shortcut" version is the Switch statement form:
CASE expression
WHEN val1 THEN r1
WHEN val2 THEN r2
WHEN val3 THEN r2
END
is the same as
SWITCH(expression){
CASE val1: r1
CASE val2: r2
CASE val3: r3
}
which is to say the VAL things need to evaluate down, thus for you stumbled upon cases, you are writing extra boolean logic, which resolves down to a boolean answer. And as the doc's note, for a expression to match a value they need to be of the same type of can be auto converted.
thus this gives a SQL error:
select
case false
when true then 1
when 'bob' then 2
end;
Boolean value 'bob' is not recognized
because the second value cannot be auto converted to the same type as the case expression, which is a boolean value.

Using function inside CASE

I am trying to use the SUBSTR and NVL functions inside the case. The case is in the where clause of the select statement.
The code below gives the following error:
ORA-00905: missing keyword
AND ( CASE
WHEN SUBSTR(upper(p_open_invoice),1,1) = 'Y' THEN
NVL(P.AMOUNT_DUE_REMAINING,0) = 0
ELSE
1=1
END)
This looks like a syntax error around equal operator of NVL function.
That is not how case expressions work (in Oracle) -- there is no boolean type to return.
The simplest method is to remove the `case and express this as simple logic:
AND (SUBSTR(upper(p_open_invoice), 1, 1) <> 'Y' OR
COALESCE(P.AMOUNT_DUE_REMAINING, 0) = 0
)
If p_open_invoice can be NULL, you need to take that into account as well.
You cannot use a collation as a result for case..when statements, it's better converting the condition to
AND (( SUBSTR(upper(p_open_invoice),1,1) = 'Y' AND NVL(P.AMOUNT_DUE_REMAINING,0) = 0 )
OR SUBSTR(upper(p_open_invoice),1,1) != 'Y' )
If you're accustomed to programming in PL/SQL you may have seen that there's a BOOLEAN type in PL/SQL. However, this is not true in the Oracle database itself. The way I usually work around this is to use character expressions which return 'Y' or 'N' instead of TRUE or FALSE.
Keeping this in mind - if you really want to use a CASE expression similar to what you had originally you can use the following:
AND CASE
WHEN SUBSTR(upper(p_open_invoice),1,1) = 'Y'
THEN CASE
WHEN NVL(P.AMOUNT_DUE_REMAINING,0) = 0 THEN 'Y'
ELSE 'N'
END
ELSE 'Y'
END = 'Y'
Here the CASE expression returns either 'Y' or 'N', which is then compared with 'Y'.

Is there boolean type for column in Oracle SQL?

I tried to:
select 1>2 from dual;
but got:
ORA-00923: FROM keyword not found where expected
Is there boolean type for column expression in Oracle SQL?
I able to do:
select case when 1>2 then 'T' else 'F' end from dual;
Originally I tried to compare date fields and the quickest way I found was getting difference and look to sign...
UPDATE I tried SIGN function, I don't know if it is vendor specific extension:
select SIGN(1-2) from dual;
select SIGN(DATE '2017-01-02' - DATE '2017-02-12') from dual;
but this trick doesn't work for strings...
No there is not, you can use 0 and 1 just as yes/no.
If you need to get the result 1 if something is true and 0 if it is false, you can use a case expression:
select case when (any_logical_condition_here) then 1 else 0 end as my_col
from ....
where ....
For example:
select case when 1 > 2 then 1 else 0 end as bool_result
from dual;
BOOL_RESULT
---------------------------------------
0
NOTE though - "Boolean" refers strictly to the TRUE/FALSE logic, it has no place for UNKNOWN. When you deal with null, as you must in SQL, you need three-valued logic. The case expression as written above returns 1 when the logical condition is true and 0 otherwise. Try it with 1 > null - the truth value is UNKNOWN, the case expression will return 0.

What's the equivalent of ELSEIF in Apache hive?

I'm looking for a conditional structure in Apache Hive like the following Java code:
if (condition) value
elseif (condition) value
...
else value
Is there a way to do this in HiveQL?
You can use the case statement in HIVE
CASE Statement
The syntax for the case statement is:
CASE [ expression ]
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
WHEN conditionn THEN resultn
ELSE result
END
Here expression is optional. It is the value that you are comparing to the list of conditions. (ie: condition1, condition2, ... conditionn).
All the conditions must be of same datatype. Conditions are evaluated in the order listed. Once a condition is found to be true, the case statement will return the result and not evaluate the conditions any further.
All the results must be of same datatype. This is the value returned once a condition is found to be true.
IF no condition is found to be true, then the case statement will return the value in the ELSE clause. If the ELSE clause is omitted and no condition is found to be true, then the case statement will return NULL
Example:
CASE Fruit
WHEN 'APPLE' THEN 'The owner is APPLE'
WHEN 'ORANGE' THEN 'The owner is ORANGE'
ELSE 'It is another Fruit'
END
The other form of CASE is
CASE
WHEN Fruit = 'APPLE' THEN 'The owner is APPLE'
WHEN Fruit = 'ORANGE' THEN 'The owner is ORANGE'
ELSE 'It is another Fruit'
END

SQL INNERJOIN with a switch case and if statement in select

Please help:
I have to create a column based on an expression from other columns,
but before that expression hits, there has to be a date check
if the date is before a specific date- it must do an expression, if the date is after said date, it must do another expression,
THEN: theres a unique column that has the digits 1-10 in it, each number represents a different expression.
the inner join and selecting the rows are fine, its just the switch and if expression that are beating me
basically the statement needs to look like this
select column1 if(date<neededDate)
{select case ExpressionColumn
when 1 //do stuff
when 2 // do stuff
else// do nothing
}
select column1 if(date>neededDate)
{select case ExpressionColumn
when 1 //do stuff
when 2 // do stuff
else// do nothing
}
i hope this made sense
You need two case statement nested within another case statement, it can be done like following
SELECT CASE WHEN date > neededDate THEN
CASE ExpressionColumn
WHEN 1 THEN '1'
WHEN 2 THEN '2'
ELSE 'null'
END
WHEN date < neededDate THEN
CASE ExpressionColumn
WHEN 1 THEN '1'
WHEN 2 THEN '2'
ELSE 'null'
END
ELSE 'null'
END
FROM YourTable;
you have your syntax wrong:
select case sign(datediff('s', date, neededDate)) -- precision: second
when 0 then -- case missing in your spec !
else
case ExpressionColumn
when 1 then -- case 1
when 2 then -- case 2
else -- whatever
end
end
from whatever
;
replace each comment with the appropriate expression over columns.
in your case a searched case expression might be more convenient:
select case
when (date < neededDate) then
-- note the difference: instead of 'case x when y then ...' you write 'case when b then ...'
case ExpressionColumn
when 1 then -- case 1
when 2 then -- case 2
else -- whatever
end
when (date > neededDate) then
case ExpressionColumn
when 1 then -- case 1
when 2 then -- case 2
else -- whatever
end
else -- this is missing from your spec!
end
from whatever
;
You need to check CASE..WHEN..THEN in Sql server
Simple CASE expression:
CASE input_expression
WHEN when_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END
Searched CASE expression:
CASE
WHEN Boolean_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END