Postgres nested if in case query - sql

Could you tell my why the following isnt working in postgres sql?:
See updated code below
UPDATE:
I expect the query to return "0.30" as float.
This construct is only for testing purposes, i have some complex querys which depend on this conditional structure... BUt i dont know how to fix it..
Result is:
ERROR: syntax error at or near "1"
LINE 4: if 1=1 then
UPDATE:
This construction appears in a function... so I want to do following:
CREATE FUNCTION f_test(myvalue integer) RETURNS float AS $$
BEGIN
select (
case (select '1')
when '1' then
if 1=1 then
0.30::float
else
0.50::float
end
else
1.00::float
end
);
END;
$$ LANGUAGE plpgsql;
select f_test(1) as test;
Error message see above.

There is no IF expr THEN result ELSE result END syntax for normal SQL queries in Postgres. As there is neither an IF() function as in MySQL, you have to use CASE:
select (
case (select '1')
when '1' then
case when 1=1 then 0.30::float else 0.50::float end
else
1.00::float
end
);

I don't know what you're trying to achieve with this function, but here's a working version.
CREATE FUNCTION f_test(myvalue integer) RETURNS float AS $$
BEGIN
IF myvalue = 1 THEN
IF 1=1 THEN
RETURN 0.30::FLOAT;
ELSE
RETURN 0.50::FLOAT;
END IF;
ELSE
RETURN 1.0::FLOAT;
END IF;
END;
The function returns 0.3 if input value is 1, otherwise it'll return 1. Edit: Note that 0.5 is never returned by the function.

Related

How to implement a function that check a condition

I can't use boolean in a sql query.
Therefore I can't create a function that return true or false and use it to test a condition.
I must create a function that return something (1 for instance) and test it. Like that:
WITH
FUNCTION f (input INTEGER)
RETURN INTEGER
IS
BEGIN
RETURN CASE WHEN input = 1 THEN 1 ELSE 0 END;
END;
A AS (SELECT 1 a FROM DUAL)
SELECT *
FROM a
WHERE f(a.a) = 1
instead of that:
WITH
FUNCTION f (input INTEGER)
RETURN boolean
IS
BEGIN
RETURN input = 1 ;
END;
A AS (SELECT 1 a FROM DUAL)
SELECT *
FROM a
WHERE f(a.a)
Unless there is another way?
code
I've tried to use a macro but to no avail
WITH
FUNCTION ft
RETURN VARCHAR2 SQL_MACRO
IS
BEGIN
RETURN q'{
SELECT 1
FROM dual
}';
END;
FUNCTION fc
RETURN VARCHAR2 SQL_MACRO
IS
BEGIN
RETURN q'{
1=1
}';
END;
SELECT *
FROM ft()
WHERE fc()
ORA-00920: invalid relational operator
code
The BOOLEAN data type is a PL/SQL only data type and is not supported in Oracle SQL statements.
Use two constants:
0 for false, 1 (or non-zero) for true (as per the C language).
0 for no errors, non-zero for errors (as per Unix program exit codes).
'Y' for yes, 'N' for no.
'success' and 'failure'
etc.
Whatever you return is your personal preference. Document the convention you are going to use and then use it consistently so that everyone on the same project uses the same convention.
Unless there is another way?
No, just pick a convention for truthy/falsy values and stick to that.
WITH
FUNCTION f_check_int ( p_str VARCHAR2 )
RETURN VARCHAR2 ------- Y / N
IS
lv_data NUMBER;
BEGIN
lv_data := TO_NUMBER(p_str);
IF lv_data>0 AND MOD(lv_data,1)=0 THEN
RETURN 'Y';
ELSE
RETURN 'N';
END IF;
EXCEPTION
WHEN VALUE_ERROR THEN
RETURN 'N';
END;
A AS (SELECT 1 a FROM DUAL)
SELECT *
FROM a
WHERE f_check_int(a.a) = 'Y'

Return result of CASE with Posgres SQL function

I am trying to write a simple SQL function that will be used as a computed field in Hasura.io platform.
CREATE OR REPLACE FUNCTION calling_mode(calling_row calling, hasura_session json)
RETURNS text AS $$
SELECT CASE
WHEN calling_row.seekerUserId = hasura_session ->> 'x-hasura-user-id' THEN 'seeker'
WHEN calling_row.partnerUserId = hasura_session ->> 'x-hasura-user-id' THEN 'partner'
ELSE 'none'
END
$$ LANGUAGE sql STABLE;
This gives me an error missing FROM-clause entry for table "calling_row".
I tried looking through several docs, but it doesn't make any sense to me.
Probably that causes upper case letters, so if your original column name is seekerUserId, then into your function postgres converts it as seekeruserid, and that column is not found.
Try column names into double quotes, like:
CREATE OR REPLACE FUNCTION calling_mode(calling_row calling, hasura_session json)
RETURNS text AS $$
SELECT CASE
WHEN calling_row."seekerUserId" = hasura_session ->> 'x-hasura-user-id' THEN 'seeker'
WHEN calling_row."partnerUserId" = hasura_session ->> 'x-hasura-user-id' THEN 'partner'
ELSE 'none'
END
$$ LANGUAGE sql STABLE;

Oracle ORA-12704 with case expression on CLOB

I have an Oracle update statement with a case that is trying to either set or ignore a value (leave original value the same ).
With this code, either of the two individual sets compile on their own ( the two commented out ones ).
But when combined in a case statement, I get "PL/SQL: ORA-12704: character set mismatch"
The column is a CLOB column.
Alternatively is there a way to conditionally not do a set in an update statement?
LONGDESCRIPT = ( CASE v_CanUpdateAssetDescription WHEN 1 THEN p_description ELSE LONGDESCRIPT END ),
-- LONGDESCRIPT = LONGDESCRIPT,
--LONGDESCRIPT = p_description,
Apparently the character set of p_description is not the same as that of LONGDESCRIPT. In a simple assignment Oracle can work with this, but in a CASE expression all values returned from the different paths through the CASE expression must be of exactly the same type. As it appears you're doing this in PL/SQL you might try doing something like the following:
DECLARE
cCLOB_var YOUR_TABLE.LONGDESCRIPT%TYPE;
BEGIN
cCLOB_var := p_description;
UPDATE YOUR_TABLE
SET LONGDESCRIPT = CASE v_CanUpdateAssetDescription
WHEN 1 THEN cCLOB_var
ELSE LONGDESCRIPT
END
...etc...
END;
You might also try using a CAST:
UPDATE YOUR_TABLE
SET LONGDESCRIPT = CASE v_CanUpdateAssetDescription
WHEN 1 THEN CAST(p_description AS YOUR_TABLE.LONGDESCRIPT%TYPE)
ELSE LONGDESCRIPT
END
Not sure if the latter will work or not, but it might be worth a shot.
Oddly I found that to_clob did the trick.
And even more oddly, I only needed TO_CLOB for the LONGDESCRIPT value.
LONGDESCRIPT = ( CASE v_CanUpdateAssetDescription WHEN 1 THEN p_description ELSE to_clob(LONGDESCRIPT) END ),

Error: ORA-01722: invalid number

CREATE OR REPLACE FUNCTION evaluation (a DATE,m Number)
RETURN VARCHAR2
IS
BEGIN
RETURN CASE
WHEN (floor(sysdate - a) < m) THEN 'Yes'
ELSE 'No'
END;
Am i doing wrongly, when executing the following code if shows me an error like:
Error: ORA-01722: invalid number
The posted code is missing an END; (the first END ends the CASE, so a second is needed to end the procedure), but other than that it is working, provided you enter a number and not a string that cannot be converted to a number.
select evaluation(sysdate+3, 2) from dual;
YES
select evaluation(sysdate+3, '2') from dual;
YES
select evaluation(sysdate+3, 'a') from dual;
Error: ORA-01722: invalid number
Include another end # last.....
CREATE OR REPLACE FUNCTION evaluation (a DATE,m Number)
RETURN VARCHAR2
IS
BEGIN
RETURN (CASE
WHEN (floor(sysdate - a) < m) THEN 'Yes'
ELSE 'No'
END);
END;

Round to the nearest odd integer in SQL

I've found myself somewhat improbably* needing to round to the nearest ODD integer in SQL. There's a nice solution for how to round to the nearest N (2,5,10,etc) here, but nothing explicitly on odd numbers. Using Oracle 11gR2, if there are solutions particular to Oracle out there.
*Need to join my data to tables stripped from this study. The authors used a consistent bin width of 2...but sometimes it's even, and others it's odd.
You could do something like this:
DECLARE
n FLOAT;
BEGIN
n := 195.8;
SELECT
CASE
WHEN mod(FLOOR(n),2) = 0 THEN FLOOR(n)+1
ELSE FLOOR(n)
END NUM
INTO n
FROM DUAL;
dbms_output.put_line(to_char(n));
END;
/
Sometimes straightfoward is best, as people who come along after you will understand what's going on.
I don't think you need a case statement, this should do it:
SELECT
ROUND((11.9-1)/2,0)*2+1
FROM DUAL
Here is an oracle PL/SQL Function that would do that:
CREATE OR REPLACE FUNCTION ROUNDODD
(
IMPNUM IN NUMBER
) RETURN NUMBER AS
roundnum number;
oddnum number;
BEGIN
roundnum := round (IMPNUM,0);
IF mod(roundnum,2) = 1
THEN RETURN roundnum;
ELSE
IF roundnum > IMPNUM
THEN RETURN roundnum-1;
ELSE RETURN roundnum+1;
end if;
end if;
END ROUNDODD;
Arithmetic OR?
ROUND(3.14,0)|1
EDIT
Andriy correctly corrects this to FLOOR(3.64)::int|1. (which works correctly).
using modulus can help you find even/odd numbers. add 1 to the even numbers
select
case when (value % 2) <> 0 then value
else value + 1 end
from table