Binding data to a variable in a CASE WHEN statement - sql

I am writing an oracle PL/SQL compound trigger. In the code I'm querying a single value and putting it into a variable.
From there I check whether the variable is null or not. If it is, I need to assign 0 to another variable, if it isn't I assign 1.
I think this is possible with a CASE WHEN statement.
An example is as follows
//line 23 ↓
SELECT contract_end INTO contractEnd FROM contract WHERE contract_id = :new.expense_job;
//line 25 ↓
SELECT CASE WHEN contractEnd IS NOT NULL THEN
contractIDCollection(iterator).ended := 1
ELSE
contractIDCollection(iterator).ended := 0
END
FROM dual;
However, when I do this the compiler throws an error and says that I have not finished the statement.
Is this the correct way to go about doing this?
contractIDCollection is a record with parameters, the definition code is working properly
LINE/COL ERROR
-------- -----------------------------------------------------------------
23/5 PL/SQL: SQL Statement ignored
24/44 PL/SQL: ORA-00905: missing keyword

Do not try to switch from the PL/SQL scope to the SQL scope (with a SELECT statement) to try to assign the variable; just do it all in the PL/SQL scope:
IF contractEnd IS NOT NULL THEN
contractIDCollection(iterator).ended := 1;
ELSE
contractIDCollection(iterator).ended := 0;
END IF;
If you did want to incur the overheads of context-switching (don't, as you do not need to and it is likely to be slower) then you can use:
SELECT CASE WHEN contractEnd IS NOT NULL THEN 1 ELSE 0 END
INTO contractIDCollection(iterator).ended
FROM dual;
or do it all on the line before:
SELECT contract_end,
CASE WHEN contract_end IS NOT NULL THEN 1 ELSE 0 END
INTO contractEnd,
contractIDCollection(iterator).ended
FROM contract
WHERE contract_id = :new.expense_job;

Related

Is it possible to have constant function parameters in SQL?

Is it possible to have constant function parameters in SQL to make sure the values are not changed later?
Something like this doesn't work:
function my_func(
first_param constant varchar2
, second_param constant varchar2
) return varchar2
is
... -- Rest
That is not necessary as you cannot redefine an IN parameter. For example:
CREATE FUNCTION does_not_work(
a IN NUMBER,
b IN NUMBER
) RETURN NUMBER
IS
BEGIN
IF a < 2 THEN
a := 2;
END IF;
RETURN GREATEST( a, b );
END;
/
(Note: the IN keyword is optional and the default parameter direction; you would get the same error if you declared the signature without the IN keywords.)
Gives:
ORA-24344: success with compilation error
If you look at the errors:
SELECT * FROM USER_ERRORS;
Outputs:
NAME
TYPE
SEQUENCE
LINE
POSITION
TEXT
ATTRIBUTE
MESSAGE_NUMBER
DOES_NOT_WORK
FUNCTION
1
8
5
PLS-00363: expression 'A' cannot be used as an assignment target
ERROR
363
DOES_NOT_WORK
FUNCTION
2
8
5
PL/SQL: Statement ignored
ERROR
0
This tells you that you can't use an IN parameter as an assignment target.

IF-ELSE statement: create a column depending on another one

In the table JAN07, I have a column TEMPO_INTERCORSO (number(10,0)) and I want to create another column ANTE_POST (number(1)) that is '0' when TEMPO_INTERCORSO > 0 and '1' otherwise.
IF (TEMPO_INTERCORSO > 0) THEN
UPDATE JAN07 SET ANTE_POST = 1
ELSE
UPDATE JAN07 SET ANTE_POST = 0
END IF;
I've tried a lot of different ways that you can find on the web (for example the ";" before the ELSE: sometimes there is, sometimes not), but it is still not working.
IF (TEMPO_INTERCORSO = 0) THEN
Report error -
Comando sconosciuto
Some ideas?
ps= I've tried with JAN07.TEMPO_INTERCORSO too!
The following UPDATE query uses CASE...WHEN to achieve what you want:
UPDATE JAN07
SET ANTE_POST = CASE WHEN TEMPO_INTERCORSO > 0 THEN 1 ELSE 0 END
I would rather suggest Virtual Columns introduced in Oracle Database 11g Release 1. A simple CASE statement would do the rest.
For example,
SQL> CREATE TABLE t
2 (
3 TEMPO_INTERCORSO NUMBER,
4 ANTE_POST NUMBER GENERATED ALWAYS AS (
5 CASE
6 WHEN TEMPO_INTERCORSO > 0
7 THEN 1
8 ELSE 0
9 END) VIRTUAL
10 );
Table created.
Now, you need not worry about manually updating the virtual column, it will be automatically generated at run time.
Let's insert the values only in static column and see:
SQL> INSERT INTO t(TEMPO_INTERCORSO) VALUES(0);
1 row created.
SQL> INSERT INTO t(TEMPO_INTERCORSO) VALUES(1);
1 row created.
SQL> INSERT INTO t(TEMPO_INTERCORSO) VALUES(10);
1 row created.
SQL> commit;
Commit complete.
SQL> SELECT * FROM t;
TEMPO_INTERCORSO ANTE_POST
---------------- ----------
0 0
1 1
10 1
So, you have your column ANTE_POST with desired values automatically.
Conditional control IF-THEN-ELSE STATEMENT is one statement in PL/SQL. Each statement in PL/SQL ends with semi color. Hence it's written like this:
IF condition THEN
{...statements to execute when condition is TRUE...}
ELSE
{...statements to execute when condition is FALSE...}
END IF; --semi colon at the end
In your code, there is an update statement inside. Therefore, at the end of this statement there must be semi colon. Your code can be written like this:
IF (TEMPO_INTERCORSO > 0) THEN
UPDATE JAN07 SET ANTE_POST = 1; --semi colon
ELSE
UPDATE JAN07 SET ANTE_POST = 0; --semi colon
END IF; --semi colon
Some answer already suggested doing that in pure SQL rather than PL/SQL. Which I agree with.

Simple update set postgres stored procedure

I've a problem trying to make my stored procedure work.
This is my problem:
I have a table with a columns called a, in this column there are telephone numbers.
I have to add 0039 if the number starts with 1,8,3 or 0 (or leave it as is if not) and store the new number in the column b.
This is my code:
CREATE OR REPLACE FUNCTION upg_table() RETURNS void AS $$
BEGIN
IF (substring(a from 0 for 2)!='00')
AND (substring( a from 0 for 1)='3')
OR (substring(a from 0 for 1)='0')
OR (substring(a from 0 for 1)='1')
OR ( substring(a from 0 for 1)='8')
THEN
UPDATE cdr
SET
b = '0039'||a;
ELSE
UPDATE cdr
SET
b = a;
END IF;
END;
$$ LANGUAGE plpgsql;
The error is:
ERROR: the column "a" does not exist
ROW 1: SELECT substring(a from 0 for 2)!='00' AND ...
You code has two errors:
You cannot reference the column a like it was a (non-existent) plpgsql variable. You would have to loop, too. Your approach does not work at all.
You got operator precedence wrong. AND binds before OR.
But most importantly, you don't need a plpgsql function. A plain UPDATE will do the job:
UPDATE cdr
SET b = CASE WHEN left(a, 1) IN ('0', '1', '3', '8')
AND left(a, 2) <> '00'
THEN '0039' || a ELSE a END;
This updates b in all rows, but only some with a changed a.

Oracle CASE expression documentation issue

In the SQL Language Reference for Oracle 11g R2, the documentation for the simple CASE expressions says that:
You cannot specify the literal NULL for every return_expr and the else_expr.
However the following SQL executes without problem and returns null:
select case 'test'
when 'test' then null
else null
end "Null Test"
from dual;
Is this a problem with the documentation or am I missing something?
You have to have at least one not null return expression when your case expression(whether it's simple or search case expression) is used inside a PL/SQL block. In SQL this restriction is relaxed:
Is this a problem with the documentation or am I missing something
It seems like a minor documentation bug.
SQL:
SQL> select case 1
2 when 1 then null
3 else null
4 end as res
5 from dual
6 ;
Result:
RES
---
null
PL/SQL:
SQL> declare
2 l_res number;
3 begin
4 l_res := case 1
5 when 1 then null
6 else null
7 end;
8 end;
9 /
ORA-06550: line 4, column 11:
PLS-00617: at least one result in the CASE expression must not be NULL
ORA-06550: line 4, column 2:
PL/SQL: Statement ignored

Postgres nested if in case query

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.