I'm trying to assign a value to a variable based on an if statement to be used to insert into a table as part of a trigger
I'm trying to assign a value to a variable based if another variable that is calculated is great than zero.
CREATE OR REPLACE TRIGGER transactions_checking_trigger
AFTER INSERT OR UPDATE ON checking
FOR EACH ROW
DECLARE
account_type char(4);
account_num char(4);
trans_date date;
trans_amt number;
trans_type char(4);
trans_comments varchar(25);
BEGIN
account_type := 'CHEK';
trans_date := sysdate;
trans_amt := :new.balance-:old.balance;
if trans_amt > 0
trans_type := 'DEPT'
ELSE
trans_type := 'WDRW'
end if;
IF UPDATE THEN
INSERT INTO transactions (account_type, account_num, trans_date,
trans_amt, trans_type,trans_comments)
VALUES (account_type, :new.account_num,trans_date,trans_amt, trans_type,
new:trans_comments);
END IF;
END;
/
I expect the trigger to insert DEPT if trans_amt > 0 and WDRW if trans_amt < 0
Syntax is IF-THEN-ELSE; you're missing the THEN. Also, statement has to be terminated with a semi-colon.
if trans_amt > 0
then --> this
trans_type := 'DEPT'; --> semi-colon
ELSE
trans_type := 'WDRW'; --> semi-colon
end if;
A simpler option:
trans_type := case when trans_amt > 0 then 'DEPT'
else 'WDRW'
end;
This is wrong:
IF UPDATE THEN
Did you mean updating instead?
Related
I am new to mariadb trigger. I had this trigger in Oracle. Need help to convert it to mariadb:
DECLARE
v_newVal NUMBER(12) := 0;
v_incval NUMBER(12) := 0;
BEGIN
IF INSERTING AND :new.id IS NULL THEN
SELECT hvr_storyboards_id_SEQ.NEXTVAL INTO v_newVal FROM DUAL;
-- If this is the first time this table have been inserted into (sequence == 1)
IF v_newVal = 1 THEN
--get the max indentity value from the table
SELECT NVL(max(id),0) INTO v_newVal FROM hvr_storyboards;
v_newVal := v_newVal + 1;
--set the sequence to that value
LOOP
EXIT WHEN v_incval>=v_newVal;
SELECT hvr_storyboards_id_SEQ.nextval INTO v_incval FROM dual;
END LOOP;
END IF;
--used to emulate LAST_INSERT_ID()
--mysql_utilities.identity := v_newVal;
-- assign the value from the sequence to emulate the identity column
--:new.id := v_newVal;
END IF;
END;
I use a online conversion tool then manage to create it as
DECLARE
v_newVal NUMBER(12) := 0;
v_incval NUMBER(12) := 0;
BEGIN
IF INSERTING AND :new.id IS NULL THEN
SELECT hvr_storyboards_id_SEQ.NEXTVAL INTO v_newVal FROM DUAL;
-- If this is the first time this table have been inserted into (sequence == 1)
IF v_newVal = 1 THEN
--get the max indentity value from the table
SELECT NVL(max(id),0) INTO v_newVal FROM hvr_storyboards;
v_newVal := v_newVal + 1;
--set the sequence to that value
LOOP
EXIT WHEN v_incval>=v_newVal;
SELECT hvr_storyboards_id_SEQ.nextval INTO v_incval FROM dual;
END LOOP;
END IF;
--used to emulate LAST_INSERT_ID()
--mysql_utilities.identity := v_newVal;
-- assign the value from the sequence to emulate the identity column
--:new.id := v_newVal;
END IF;
END;
but I am getting this error
An exception occurred while executing 'INSERT INTO hvr_storyboards (name, updated_datetime, domain_id, ticker_id, updated_by) VALUES (?, ?, ?, ?, ?)' with params ["this is a test 6 - Ace", null, 21, null, null]: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'INSERTING' in 'field list'
what did I do wrong?
I write one dynamic SQL which the result of it is a table with 2 columns and multiple rows, I want to insert it to another table with 4 columns that 2 of them will be filled by the result of dynamic SQL, I try to use collection but don't know how to insert result to another table
CREATE OR REPLACE PROCEDURE P_C_SM_Failure_error_Code_P2P AS
v_month VARCHAR2(16); -- to get Month for each table
v_day VARCHAR2(16); -- to get day for each table
v_ERRCODE t_c_rpt_resultmsg.code%TYPE;
v_ERRMSG t_c_rpt_resultmsg.MESSAGE%TYPE;
v_param VARCHAR2(16);
v_sql VARCHAR2(3000);
v_result number;
type t_c_result is record (Err_code varchar2(2000), Err_count number);
type v_t_result is table of t_c_result index by PLS_INTEGER;
v_t1_result v_t_result;
BEGIN
v_sql :='0';
v_param := 'Gateway_G';
v_result := '0';
select to_char(sysdate - 1,'MM') into v_month from dual;
select to_char(sysdate - 1,'DD') into v_day from dual;
-- Get count of P2P
v_sql := '(select count(*), error_code from (
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC01 where
orgaccount = '''||v_param||''' and destaccount = '''||v_param||''' and
sm_status <> 1 union all
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC02 where
orgaccount = '''||v_param||''' and destaccount = '''||v_param||''' and
sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql bulk collect into v_t1_result;
--insert into t_c_rpt_result2 values (trunc(sysdate, 'DD'), v_errcount,
v_err_code,'Failure_error_Code_P2P');
--for indx in 1 .. v_t1_result.COUNT
--loop
--dbms_output.put_line (v_t1_result (indx).Err_code);
--end loop;
You may append the constant values of date and the error message to the subquery and run a dynamic insert. It should also work if you remove the outer parentheses of your dynamic sql since constants can be included in group by. Always remember to pass values as bind variables rather than concatenating them (v_param). Also, specify the column names explicitly in an INSERT statement.
v_sql := '(select count(*) as cnt, error_code
from (
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC01
where orgaccount = :x and destaccount = :x and sm_status <> 1
union all
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC02
where orgaccount = :x and destaccount = :x and sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql bulk collect into v_t1_result using v_param;
EXECUTE IMMEDIATE 'insert into t_c_rpt_result2(err_dt,err_msg,errcount,error_code)
select :dt,:msg,cnt,error_code from '|| v_sql
USING trunc(sysdate, 'DD'),'Failure_error_Code_P2P',v_param;
I think you are looking at an excellent use case for FORALL. The collection you are populating needs to be done with execute immediate since you are dynamically constructing the table name. But the insert into t_c_rpt_result2 looks static to me.
BEGIN
v_sql :=
'(select count(*) as cnt, error_code
from (
select error_code from sm_histable'
|| v_month
|| ''
|| v_day
|| '#ORASMSC01
where orgaccount = :x and destaccount = :x and sm_status <> 1
union all
select error_code from sm_histable'
|| v_month
|| ''
|| v_day
|| '#ORASMSC02
where orgaccount = :x and destaccount = :x and sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql BULK COLLECT INTO v_t1_result USING v_param;
FORALL indx IN 1 .. v_t1_result.COUNT
INSERT INTO t_c_rpt_result2 (err_dt,
err_msg,
errcount,
ERROR_CODE)
VALUES (TRUNC (SYSDATE, 'DD'),
'Failure_error_Code_P2P',
v_t1_result (indx).cnt,
v_t1_result (indx).ERROR_CODE);
END;
Find more examples of FORALL on LiveSQL here. Of course, even if your insert was dynamic, you can use FORALL - put the execute immediate directly "inside" the FORALL statement. But I don't think that complexity is justified here.
Hope that helps!
I have oracle pl/sql procedure with below:
TYPE Paycomp2 IS RECORD(
Row_Id VARCHAR2(15),
Created DATE,
Created_By VARCHAR2(15),
Last_Upd DATE,
Last_Upd_By VARCHAR2(15),
Modification_Num NUMBER(10),
Conflict_Id VARCHAR2(15),
Comp_Price NUMBER(10),
Access_Level VARCHAR2(30),
Comp_Name VARCHAR2(30),
Depends_On VARCHAR2(30),
Gold_Cat VARCHAR2(30),
Order_Type VARCHAR2(30),
Parent_Id VARCHAR2(15),
Price_Plan VARCHAR2(30),
TYPE VARCHAR2(30),
Check_Flag VARCHAR2(1),
PREPAID_INIT_PRICE number(10),
DB_LAST_UPD date,
DB_LAST_UPD_SRC varchar2(50),
Unit_Type varchar2(30),
M2M_CATEGORY varchar2(30));
TYPE Paycomp IS REF CURSOR;
C2 Paycomp;
Cursor2 Paycomp2;
when I do the below operation
FETCH C2 INTO Cursor2;
I am getting this error :
ORA-01007: variable not in select list error.
This piece of script has worked previously.
How to resolve this issue?
script
Vordertype := 'Migration Prepaid - Postpaid';
Curcomp_Sql := Curcomp_Sql || Vordertype || '''' || ' union all ' || '' || Curcomp2sql || '' ||
Vordertype || '''';
OPEN C2 FOR Curcomp_Sql;
Sadmin.Pkg_Spliter.Prcsplitchar(Ppaycompstr, ';', Arrcomplist);
Vtotalcompprc := 0;
Arrcount := Arrcomplist.Count;
BEGIN
Dbms_output.put_line('reached17');
LOOP
FETCH C2
INTO Cursor2;
Dbms_output.put_line('reached18');
EXIT WHEN C2%NOTFOUND;
-- Processing each entry from Array
Compfndflg := 0;
dbms_output.put_line('arrCount 0: reached');
FOR Counter IN 1 .. Arrcount
LOOP
Vstrcommand := Arrcomplist(Counter);
dbms_output.put_line('arrCount : reached');
Sadmin.Pkg_Spliter.Prcsplitchar(Vstrcommand, '?', Arrdisclist);
IF Arrdisclist.Count <> 0 THEN
dbms_output.put_line('arrCount : reached1');
-- Extracting the ? seperated values and putting them into variables
Vcompname := Arrdisclist(1);
--dbms_output.put_line(CURSOR2.comp_name||':- count -'||COUNTER||'--'||VCOMPNAME);
BEGIN
-- Added by Accenture
IF Vcompname IS NOT NULL THEN
--dbms_output.put_line(CURSOR2.comp_name||':- count -'||COUNTER||'--'||ARRDISCLIST(1)||'-'||ARRDISCLIST(2)||'-'||ARRDISCLIST(3));
SELECT COUNT(0)
INTO v_Count_Exist
FROM Siebel.Cx_Paycomp_Mtx a, Siebel.Cx_Paycomp_Mtx b
WHERE a.Row_Id = b.Parent_Id
AND a.Order_Type = Vordertype
AND b.Type = 'Payment Component'
AND b.Comp_Name = Vcompname;
IF (v_Count_Exist = 0) THEN
Err_Msg := 'Invalid Payment Component in String';
Result_Out := '74';
Errflg := 1;
--dbms_output.put_line('Counter 2' || counter);
--dbms_transaction.rollback;
RAISE Error_Out;
END IF;
END IF;
--dbms_output.put_line('Counter 3' || CURSOR2.comp_name);
IF Vcompname = Cursor2.Comp_Name
--and VCOMPNAME != '3'
THEN
Compfndflg := 1;
EXIT;
END IF;
END;
END IF;
END LOOP;
---DBMS_OUTPUT.PUT_LINE('VCOMPNAME, COMPFNDFLG'||VCOMPNAME||','||COMPFNDFLG);
--dbms_output.put_line('CURSOR2.comp_name :'||CURSOR2.comp_name||' - COMPFNDFLG :'||COMPFNDFLG);
IF Compfndflg != 1 THEN
IF Temp_Comp_String IS NULL THEN
Temp_Comp_String := Cursor2.Comp_Name || '?0?;';
---DBMS_OUTPUT.PUT_LINE('STRING 1'||TEMP_COMP_STRING);
ELSE
Temp_Comp_String := Temp_Comp_String || Cursor2.Comp_Name || '?0?;';
---DBMS_OUTPUT.PUT_LINE('STRING 2'||TEMP_COMP_STRING);
END IF;
--- END IF;
ELSE
IF Temp_Comp_String IS NULL THEN
Temp_Comp_String := Arrdisclist(1) || '?' || Arrdisclist(2) || '?' ||
Arrdisclist(3) || ';';
---DBMS_OUTPUT.PUT_LINE('STRING 3'||TEMP_COMP_STRING);
ELSE
Temp_Comp_String := Temp_Comp_String || Arrdisclist(1) || '?' || Arrdisclist(2) || '?' ||
Arrdisclist(3) || ';';
---DBMS_OUTPUT.PUT_LINE('STRING 4'||TEMP_COMP_STRING);
END IF;
-- end if;
--- END IF;
END IF;
END LOOP;
END;
Curcomp_Sql VARCHAR2(2000) := 'SELECT mtx2.*
FROM siebel.CX_PAYCOMP_MTX mtx1, siebel.CX_PAYCOMP_MTX mtx2
WHERE mtx2.parent_id = mtx1.row_id
AND mtx2.comp_name <> ''Security Deposit''
AND mtx2.TYPE = ''Payment Component''
AND mtx1.order_type = ''';
Curcomp2sql VARCHAR2(2000) := 'SELECT mtx2.*
FROM siebel.CX_PAYCOMP_MTX mtx1, siebel.CX_PAYCOMP_MTX mtx2
WHERE mtx2.parent_id = mtx1.row_id
AND mtx2.comp_name = ''Security Deposit''
AND mtx2.TYPE = ''Payment Component''
AND mtx2.depends_on = ''ACCESS LEVEL''
AND mtx1.order_type = ''';
A simplified version of what you're seeing, with a dummy table and simple anonymous block:
create table t42 (id number, some_value varchar2(10));
declare
type t_rec is record(id number, some_value varchar2(10));
l_rec t_rec;
l_cur sys_refcursor;
begin
open l_cur for 'select * from t42';
fetch l_cur into l_rec;
close l_cur;
end;
/
PL/SQL procedure successfully completed.
To get the error you're seeing I just need to remove one of the table columns:
alter table t42 drop column some_value;
and run exactly the same code again:
declare
type t_rec is record(id number, some_value varchar2(10));
l_rec t_rec;
l_cur sys_refcursor;
begin
open l_cur for 'select * from t42';
fetch l_cur into l_rec;
close l_cur;
end;
/
ORA-01007: variable not in select list
ORA-06512: at line 10
The field list in the record type declared in the PL/SQL block no longer matches the column type in the cursor query. The record variable you're fetching into expects two columns (in my version; 22 in yours), but the query only gets one value.
You can (some would say should) specify all the columns you're selecting explicitly, but assuming you're actually referring to them all later you would then have done the equivalent of:
open l_cur for 'select id, some_value from t42';
which would still have errored after the column removal, though a bit more helpfully perhaps:
ORA-00904: "SOME_VALUE": invalid identifier
ORA-06512: at line 9
Since you're currently intending to get all columns from a single table, you could also have used the %rowtype syntax instead of your own record type:
declare
l_rec t42%rowtype;
l_cur sys_refcursor;
begin
open l_cur for 'select * from t42';
fetch l_cur into l_rec;
close l_cur;
end;
/
which with this trivial example runs successfully. You'll still have a problem though as soon as you refer to the removed column, assuming it's still part of the record:
declare
l_rec t42%rowtype;
l_cur sys_refcursor;
begin
open l_cur for 'select * from t42';
fetch l_cur into l_rec;
dbms_output.put_line(l_rec.some_value);
close l_cur;
end;
/
ORA-06550: line 7, column 30:
PLS-00302: component 'SOME_VALUE' must be declared
ORA-06550: line 7, column 3:
PL/SQL: Statement ignored
(Using %rowtype would give you some breathing space if a column was added, as it would just be ignored, unless and until you added code to refer to that record field. But with your code you'd get ORA-00932 inconsistent data types, rather than ORA-01007, so that doesn't seem to be what's happening here.)
If you aren't referring to the removed column/field anywhere then you shouldn't be selecting it anyway. Change the record type to only include the fields you actually need, and only get the corresponding columns in the cursor query.
If you are referring to the removed column/field then you're stuck anyway - you'll have find out what was removed and why, and then either fix your code to not refer to it (if that makes sense), or get that change reverted.
I have one table that holds a record for each customer (main table). I then have a table with additional detail for some customers. The additional detail table sometimes has no records for a record in the main table. Sometimes the detail table has multiple records for a record in the main table & if this is the case I need the most recent record (hence the max subselect).
The trouble is my function only returns values for the few records in the detail table. If I comment out the portion of the function that looks at the detail table and just return the STAT3 value it seems to work. How do I make the second select statment below only apply if there is a result for that query?
create or replace FUNCTION "F_RETURN_STAT" (
N_UNIQUE IN NUMBER)
RETURN VARCHAR2
IS
V_STAT3 varchar2(20);
V_STAT varchar2(20);
V_STAT2 varchar2(20);
D_ACTDATE date;
D_STARTDATE date;
BEGIN
select expire into D_ACTDATE
from main_table a
where a.uniquefield = N_UNIQUE;
IF
D_ACTDATE > SYSDATE
or
D_ACTDATE is null
then
V_STAT :='TRUE';
else
v_STAT :='FALSE';
end if;
select b.startdate into D_STARTDATE
from main_table a, detail_table b
where a.uniquefield= b.main_table_id(+) and
b.main_table_id = N_UNIQUE and
b.uniquefield in
(select max(c.uniquefield) from detail_table c group by main_table_id);
if
D_STARTDATE is not null
then
V_STAT2 :='FALSE';
end if;
if
V_STAT2 ='FALSE'
then
V_STAT3 :='FALSE';
ELSE
V_STAT3 := V_STAT;
end if ;
RETURN(V_STAT3);
end;
I think this version of your function will solve your problem:
CREATE OR REPLACE FUNCTION f_return_stat(n_unique IN NUMBER)
RETURN VARCHAR2 IS
v_stat3 VARCHAR2(20);
v_stat VARCHAR2(20);
v_stat2 VARCHAR2(20);
d_actdate DATE;
d_startdate DATE;
BEGIN
--First Query
SELECT expire
INTO d_actdate
FROM main_table a
WHERE a.uniquefield = n_unique;
IF d_actdate > SYSDATE OR d_actdate IS NULL THEN
v_stat := 'TRUE';
ELSE
v_stat := 'FALSE';
END IF;
BEGIN
--Second Query
SELECT b.startdate
INTO d_startdate
FROM detail_table b
WHERE b.main_table_id = n_unique
AND b.uniquefield IN (SELECT MAX(c.uniquefield)
FROM detail_table c
GROUP BY main_table_id);
EXCEPTION
WHEN NO_DATA_FOUND THEN
d_startdate := NULL;
END;
IF d_startdate IS NOT NULL THEN
v_stat2 := 'FALSE';
END IF;
IF v_stat2 = 'FALSE' THEN
v_stat3 := 'FALSE';
ELSE
v_stat3 := v_stat;
END IF;
RETURN (v_stat3);
END;
In your version of the second query, your join (a.uniquefield= b.main_table_id) and your filter (b.main_table_id = N_UNIQUE) are equivalent, so main_table a can be removed altogether. The only reason to leave it in is to make sure that your query always returns a row. If you use exception handling to catch the NO_DATA_FOUND exception, that need goes away and you can simplify your query to just select from detail_table b.
I believe there could be a more efficient way however this might do the job:
SELECT b.startdate
INTO d_startdate
FROM detail_table b
WHERE b.main_table_id = n_unique
and
(b.uniquefield in
(select max(c.uniquefield) from detail_table c group by main_table_id)
or b.uniquefield is null);
I have this query and it's not updating into the database. The given "where" clause is valid. When I run the query independently, it works fine but in this Procedure it's not working. There is no exception or no error. Could you guys help me in figuring out where the problem is?
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET COUNTRY_CODE = :v1 WHERE col_id = :v2'
USING l_vc_CountryCode, l_vc_ColId;
if SQL%ROWCOUNT > 1 THEN
inserts := inserts + 1;
counter := counter + 1;
IF counter > 500 THEN
counter := 0;
COMMIT;
END IF;
END IF;
I didn't write the commit code before. Just to clarity.
I suppose that col_id is the primary key. So in the update statement
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET COUNTRY_CODE = :v1 WHERE col_id = :v2'
USING l_vc_CountryCode, l_vc_ColId;
you are always updating at most one row and thus the condition
SQL%ROWCOUNT > 1
is never true ( 1 is not > 1 )
So if you don't have any other commit statement in your procedure, you will never commit those updates.
By the way: what is the purpose of this
if SQL%ROWCOUNT > 1 THEN
inserts := inserts + 1;
counter := counter + 1;
IF counter > 500 THEN
counter := 0;
COMMIT;
END IF;
END IF;
why don't you just commit at the end of your work?
The following code works okay (ie updates the row).
I suspect your error is elsewhere.
For example, if you don't initialise COUNTER, the increment will still leave it as null and it will never commit.
Or, l_vc_ColId may be the wrong datatype and suffering from an invalid conversion.
declare
v_emp_id number := 7839;
v_name varchar2(4) := 'DING';
v_tab varchar2(3) := 'EMP';
begin
execute immediate 'update '||v_tab||
' set ename = :v_name Where empno = :v_emp_id'
using v_name, v_emp_id;
dbms_output.put_line('C:'||sql%rowcount);
end;
you may want to reconsider your design if your using dynamic sql to change the "dest" table in thousands of updates.
Much better to know your dest and use bind variables for the where conditions. then you can commit every x rows using mod or similar:
if (mod(v_ctr, 1000) = 0) then
commit;
end if;
But for your example, Marcin is correct, if you are updating only 1 row at a time, then
if SQL%ROWCOUNT > 1
will never be true;
EDIT:
A simple example knowing your "dest" table:
declare
cursor sel_cur is
select col1, col2, from sourceTable where col3 = 'X';
v_ctr pls_integer := 0;
begin
for rec in sel_cur
loop
v_ctr := v_ctr + 1;
-- implicit bind variables used
update destTable
set col1 = rec.col1,
col2 = rec.col2
where col3 = 'Z';
if (mod(v_ctr, 1000) = 0) then
commit;
end if;
end loop;
exception
when others then rollback;
raise;
end;
If using dynamic SQL, a simple example using explicit bind variables (USING clause) from Oracle docs:
CREATE OR REPLACE PROCEDURE raise_emp_salary (column_value NUMBER,
emp_column VARCHAR2, amount NUMBER) IS
v_column VARCHAR2(30);
sql_stmt VARCHAR2(200);
BEGIN
-- determine if a valid column name has been given as input
SELECT COLUMN_NAME INTO v_column FROM USER_TAB_COLS
WHERE TABLE_NAME = 'EMPLOYEES' AND COLUMN_NAME = emp_column;
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value;
IF SQL%ROWCOUNT > 0 THEN
DBMS_OUTPUT.PUT_LINE('Salaries have been updated for: ' || emp_column
|| ' = ' || column_value);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Invalid Column: ' || emp_column);
END raise_emp_salary;
/
For more reading, see here.
Hope this helps, happy coding
Execute immediate needs explicit commit. I guess you checked that ?