unable to create Procedure - sql

Table a:
PROTOCOL VARCHAR2(20)
Table b:
YEAR NUMBER(4)
MONTH VARCHAR2(20)
PROTOCOL VARCHAR2(20)
DATE1 DATE
My procedure code:
CREATE PROCEDURE his
#Year NUMBER(4),
#Month VARCHAR2(20)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION trninsert
DECLARE ##date DATE
SET ##date = sysdate;
INSERT INTO b (Year, month, date1, protocol)
(select #Year, #Month, ##date,* from a)
COMMIT TRANSACTION trninsert
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION trninsert
END CATCH
END
I am using plsql developer and it is showing errors in procedure.

you've written this a mysql type syntax.
oracle would be:
CREATE PROCEDURE his(p_year b.year%type,
p_month b.month%type)
AS
BEGIN
INSERT INTO b (Year, month, date1, protocol)
select p_year, p_month, sysdate, a.protocol
from a;
commit;
END;
though its bad form to commit in the procedure.
eg:
SQL> CREATE PROCEDURE his(p_year b.year%type,
2 p_month b.month%type)
3 AS
4 BEGIN
5 INSERT INTO b (Year, month, date1, protocol)
6 select p_year, p_month, sysdate, a.protocol
7 from a;
8 commit;
9 END;
10 /
Procedure created.
SQL> insert into a values('prot a');
1 row created.
SQL> exec his(2012, 10)
PL/SQL procedure successfully completed.
SQL> select * from b;
YEAR MONTH PROTOCOL DATE1
---------- -------------------- -------------------- ---------
2012 10 prot a 06-FEB-13
SQL>

Your procedure is not in a valid format: Change your entire structure with,
CREATE [OR REPLACE] PROCEDURE procedure_name
[ (parameter [,parameter]) ]
IS
[declaration_section]
BEGIN
executable_section
[EXCEPTION
exception_section]
END [procedure_name];
For more parameters: Click here

yeah you have not use the plsql syntax:
Code will be:
CREATE OR REPLACE PROCEDURE his
(Year b.year%type,
Month b.month%type)
AS
BEGIN
INSERT INTO b (Year, month, date1, protocol)
VALUES select Year, Month, sysdate,a.protocol from a ;
COMMIT;
END;

Related

need to create a temporary table inside my procedure which has a cursor in it

Procedure code below :: TYPE line has errors while compilation.let me the know the correct usage of table creation here.
CREATE OR REPLACE PROCEDURE bulk_order_export
(
startdate IN varchar2,
enddate IN varchar2,
batchsize IN varchar2
)
IS
bulkorderdata_cursor sys_refcursor ;
p_query_string VARCHAR2(100);
TYPE FBL_BACKUP_ORDER IS TABLE OF DPS_USER%TYPE;
temp_order_id FBL_BACKUP_ORDER;
BEGIN
p_query_string := 'SELECT ID FROM abc_order WHERE REGISTRATION_DATE BETWEEN :startDate AND :endDate';
OPEN bulkorderdata_cursor FOR p_query_string USING startdate, enddate;
LOOP
FETCH bulkorderdata_cursor BULK COLLECT into temp_order_id LIMIT batchsize;
FORALL i IN 1..temp_order_id.count
INSERT INTO FBL_BACKUP_ORDER VALUES(temp_order_id(i));
--COMMIT;
DBMS_OUTPUT.PUT_LINE('Commit '||temp_order_id.count||' inserted rows');
Total := Total+temp_order_id.count;
EXIT WHEN bulkorderdata_cursor%NOTFOUND;
END LOOP;
CLOSE bulkorderdata_cursor;
END;
With regard to DPS_USER%TYPE, I assume that is a table? If so, then the syntax is: DPS_USER%ROWTYPE.
Then you need to make sure your variables are defined, batchsize is numeric, and then you have sorted out some syntax, and you'll be good to go
SQL> create table DPS_USER ( id int );
Table created.
SQL> create table abc_order ( id int );
Table created.
SQL> create table FBL_BACKUP_ORDER ( id int );
Table created.
SQL>
SQL>
SQL> CREATE OR REPLACE PROCEDURE bulk_order_export
2 (
3 startdate IN varchar2,
4 enddate IN varchar2,
5 batchsize IN int
6 )
7 IS
8 bulkorderdata_cursor sys_refcursor ;
9 p_query_string VARCHAR2(100);
10 TYPE FBL_BACKUP_ORDER IS TABLE OF DPS_USER%ROWTYPE;
11 temp_order_id FBL_BACKUP_ORDER;
12 total int;
13 BEGIN
14
15 p_query_string := 'SELECT ID FROM abc_order WHERE REGISTRATION_DATE BETWEEN :startDate AND :endDate';
16 OPEN bulkorderdata_cursor FOR p_query_string USING startdate, enddate;
17 LOOP
18 FETCH bulkorderdata_cursor BULK COLLECT into temp_order_id LIMIT batchsize;
19 FORALL i IN 1..temp_order_id.count
20 INSERT INTO FBL_BACKUP_ORDER VALUES temp_order_id(i);
21 --COMMIT;
22 DBMS_OUTPUT.PUT_LINE('Commit '||temp_order_id.count||' inserted rows');
23 Total := Total+temp_order_id.count;
24 EXIT WHEN bulkorderdata_cursor%NOTFOUND;
25 END LOOP;
26 CLOSE bulkorderdata_cursor;
27 END;
28 /
Procedure created.

global temporary table in db2 stored procedure

Just getting into DB2, and have decided to use global temporary table in my stored proc for my task.
The task would be the next:
just populate some data for each day (during for example 5 days), selecting random rows from the other table
I'm getting my date like:
select id from (
select id, rand() rnd from source_table)
where rnd>0
order by rnd
fetch first 1000 rows only
I wanted to store somewhere that list of int to reuse them. The idea was the next -
create table test (id int, dt date);
create or replace procedure proc1 ()
begin
declare v_start date default '2018-05-25';
declare v_end date default '2018-05-30';
declare v_dml varchar(8000);
/* this part so far doesn't work
declare global temporary table
session.temp_tab(id int)
not logged on commit preserve;
insert into session.temp_tab(id)
select id from my_table;*/
while v_start <= v_end DO
set v_dml = 'insert into test (id, dt)
with t as (
select 1 id, '''||v_start||''' dt from sysibm.dual
union
select 2 id, '''||v_start||''' dt from sysibm.dual
union
select 3 id, '''||v_start||''' dt from sysibm.dual)
select *
from t
where id in (1,3)';
/*instead of 1,3 I would like to have list of values in some temp
table/array..., which I'll get
from the other table and can just use duriing this proc
I don't want to use sub select, because I'll get every time some random
data. But also I need that list for filter in several insert/update
statements*/
set v_start = v_start +1 day;
execute immediate v_dml;
commit;
end while;
end
P.S. I use DB2 LUW v10.5.0.7
UPD_1:
I would like to do DDL and DML operation in one loop. For example I want to add partititon and then insert the data to the same table. like this:
create or replace procedure proc1 (
in in_rep int)
begin
declare v_dt date;
declare v_end_dt date;
declare v_add_part varchar(1024);
declare v_id int;
declare v_next_id int;
select max(id), max(dt)
into v_id, v_dt
from test;
set v_end_dt = v_dt + in_rep day;
while v_dt < v_end_dt DO
set v_dt = v_dt +1 day;
set v_next_id = v_id+1;
set v_add_part = 'alter table TEST
add PARTITION part_'||v_next_id||'
starting from '||v_next_id||' ending at '||v_next_id;
execute immediate v_add_part;
insert into test (id, dt)
select v_next_id, v_dt
from sysibm.dual;
end while;
end
In this case I would get an error, SQLCODE=-327, SQLSTATE=22525
THE ROW CANNOT BE INSERTED BECAUSE IT IS OUTSIDE THE BOUND OF THE PARTITION RANGE FOR THE LAST PARTITION.
Cause of I'm trying to alter table and insert in the same time, not step by step. But can't really get how to do it step by step excep of replace insert with dynamic sql, like:
set v_add_part = 'alter table TEST
add PARTITION part_'||v_next_id||'
starting from '||v_next_id||' ending at '||v_next_id;
set v_ins = 'insert into test (id, dt)
select '||v_next_id||','''||v_dt||'''
from sysibm.dual';
execute immediate v_add_part;
execute immediate v_ins;
Here is an example of using the RAND() function to populate the session table.
Notice that the insert statement gets compiled only one time, but executed as many times as the date-range.
For production use you should add relevant error-handling.
create or replace procedure proc1 ()
language sql
specific proc1
begin
declare v_start date default '2018-05-25';
declare v_end date default '2018-05-30';
declare v_dml varchar(8000);
declare global temporary table
session.temp_tab(id int not null)
with replace not logged on commit preserve rows;
insert into session.temp_tab(id)
select int(rand()*1000) as random
from my_table order by random fetch first 1000 rows only;
set v_dml = 'insert into test (id, dt)
select t.id ,cast(? as date) from session.temp_tab as t ' ;
prepare s1 from v_dml;
while v_start <= v_end do
execute s1 using v_start;
set v_start = v_start + 1 day;
end while;
commit;
end
If you use Data Studio, that will parse your code locally and hi-light any syntax errors. The procedure creates for me (on Db2 11.1 anyway) once I added the work ROWS after PRESERVE
create or replace procedure proc1 ()
begin
declare v_start date default '2018-05-25';
declare v_end date default '2018-05-30';
declare v_dml varchar(8000);
-- this part so far doesn't work
declare global temporary table
session.temp_tab(id int)
not logged on commit preserve rows;
insert into session.temp_tab(id)
select id from my_table;
while v_start <= v_end DO
set v_dml = 'insert into test (id, dt)
with t as (
select 1 id, '''||v_start||''' dt from sysibm.dual
union
select 2 id, '''||v_start||''' dt from sysibm.dual
union
select 3 id, '''||v_start||''' dt from sysibm.dual)
select *
from t
where id in (1,3)';
/*instead of 1,3 I would like to have list of values in some temp
table/array..., which I'll get
from the other table and can just use duriing this proc
I don't want to use sub select, because I'll get every time some random
data. But also I need that list for filter in several insert/update
statements*/
set v_start = v_start +1 day;
execute immediate v_dml;
commit;
end while;
end
BTW your code would be better (IMHO) using a variable and static SQL rather than dynamically building a SQL statement. Also you can use VALUES with multiple rows, no need to select from a dummy DUAL tables.
I'm not sure what your task is, but I'm not sure you are close to the best solution here... ;-)

Oracle procedure insert into table from another table

I have this code from trigger and now i need to create procedure because i cant use trigger.
CREATE OR REPLACE TRIGGER LIVE_MATCHES_TO_MATCHES
instead of insert ON LIVE_MATCHES
for each row
declare
p_priority number:= 1;
p_sport number:=0;
begin
insert into matches(sub_list , priority , sport, created)
select :new.comp_name , p_priority, p_sport,sysdate
from dual
where not exists (
select 1 from matches
where sub_list = :new.comp_name);
end;
this is procedure :
CREATE OR REPLACE PROCEDURE LIVE_MATCHES_SOCCER_T IS
p_priority number := 1;
p_sport number:=0;
begin
INSERT INTO matches("sub_list","priority","sport","created")
SELECT LIVE_MATCHES.COMP_NAME,p_priority,p_sport, sysdate
FROM LIVE_MATCHES WHERE LIVE_MATCHES.COMP_NAME <> matches.SUB_LIST;
commit;
end;
but I m getting error that matches.sub_list is invalid identifier.
How will i create procedure that will insert into table only if sub_list is different from comp_name.. I will set up job that will call this procedure every 5 minutes..
You can use MERGE statement
CREATE OR REPLACE
PROCEDURE PR_INSRT_INTO_MATCHES
IS
P_PRIORITY NUMBER := 1;
P_SPORT NUMBER := 0;
BEGIN
MERGE INTO MATCHES M USING
(SELECT DISTINCT COMP_NAME AS COMP_NAME FROM LIVE_MATCHES
) LM ON (LM.COMP_NAME=M.SUB_LIST)
WHEN NOT MATCHED THEN
INSERT
(
M.SUB_LIST,
M.PRIORITY,
M.SPORT,
M.CREATED
)
VALUES
(
LM.COMP_NAME,
P_PRIORITY,
P_SPORT,
SYSDATE
)
COMMIT;
END;
I think you want:
INSERT INTO matches("sub_list","priority","sport","created")
SELECT lm.COMP_NAME, lm.p_priority, lm.p_sport, sysdate
FROM LIVE_MATCHES lm
WHERE NOT EXISTS (SELECT 1
FROM matches m
WHERE lm.COMP_NAME <> m.SUB_LIST
);
Unless your column names are lower-case (which can only be done in Oracle by using quotes when you create them - and which is not a particularly good idea in any case), then your stored procedure won't work, as you're quoting lower-case identifiers in it. Try this instead:
CREATE OR REPLACE PROCEDURE LIVE_MATCHES_SOCCER_T IS
p_priority number := 1;
p_sport number := 0;
begin
INSERT INTO matches
( sub_list, priority, sport, created )
SELECT LIVE_MATCHES.COMP_NAME, p_priority, p_sport, sysdate
FROM live_matches
WHERE NOT EXISTS ( SELECT 1 FROM matches WHERE LIVE_MATCHES.COMP_NAME = matches.SUB_LIST );
commit;
end;

Stored proc date query is not working

I am stuck at comparing two dates in plsql programming.
I have 2 stored procedures. The first stored procedure returns me date column as OUT param.
I am passing 1st output param is as input param for 2nd stored procedure.
But my query not returning correct value.
Stored procedure #1:
PROCEDURE SP_FIRST_COMPLETE(TASK_ID IN VARCHAR2, FIRST_COMPLETE_DT OUT DATE)
IS
...
BEGIN
...
...
DBMS_OUTPUT.PUTLINE('First completed dt is:= '||FIRST_COMPLETE_DT);
.....
end;
Stored procedure #2:
PROCEDURE SP_NOT_FIRST_COMPLETE(TASK_ID IN VARCHAR2, FIRST_COMPLETE_DT IN DATE, FIRST_COMPLETE_DT1 OUT DATE)
IS
....
BEGIN
DBMS_OUTPUT.PUTLINE('First completed dt is:= '||FIRST_COMPLETE_DT);
FOR R_ROW IN (SELECT ........ FROM .... WHERE EVENT_DT > FIRST_COMPLETE_DT ORDER BY EVENT_DT
LOOP
DBMS_OUTPUT.PUTLINE('First completed dt is:= '||FIRST_COMPLETE_DT||' QUERY RESULT DATE :='||R_ROW.EVENT_DT);
.....
END;
1ST STORED PROC OUTPUT
First completed dt is:= 14-FEB-14
2ND STORED PROC OUTPUT
First completed dt is:= 14-FEB-14
First completed dt is:= 14-FEB-14 QUERY RESULT DATE := 28-FEB-12
When I run query in SQL its giving correct result.
select ... from.... where event_dt > '18-FEB-14' order by event_dt;
Please help in in this.
Thanks
Sarma
Please look to to what it should be and compare to your code:
CREATE OR REPLACE PROCEDURE SP_FIRST_COMPLETE (
TASK_ID IN VARCHAR2,
FIRST_COMPLETE_DT IN OUT DATE)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE ('First date is:= ' ||
TO_DATE(FIRST_COMPLETE_DT, 'DD-MM-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH')
);
END;
CREATE OR REPLACE PROCEDURE SP_NOT_FIRST_COMPLETE (
TASK_ID IN VARCHAR2,
FIRST_COMPLETE_DT IN DATE,
FIRST_COMPLETE_DT1 OUT DATE)
IS
BEGIN
FIRST_COMPLETE_DT1 := TO_DATE(FIRST_COMPLETE_DT, 'DD-MM-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH');
DBMS_OUTPUT.PUT_LINE ('Second date is:= ' || FIRST_COMPLETE_DT1);
END;
The execution
DECLARE
THE_OUTPUT_DATE1 DATE ;
THE_OUTPUT_DATE2 DATE ;
BEGIN
THE_OUTPUT_DATE1 := SYSDATE;
SP_FIRST_COMPLETE (1, THE_OUTPUT_DATE1);
SP_NOT_FIRST_COMPLETE (1, THE_OUTPUT_DATE1, THE_OUTPUT_DATE2);
DBMS_OUTPUT.PUT_LINE('Output date ' || TO_DATE(THE_OUTPUT_DATE2, 'DD-MM-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH'));
END;
the DBMS output then as what you want:
First Date is:= 06-APR-14
Second Date is:= 06-APR-14
Output date: 06-APR-14

How to bulk insert data from ref cursor to a temporary table in PL/SQL

Could anyone tell me how to bulk insert data from a ref cursor to a temporary table in PL/SQL? I have a procedure that one of its parameters stores a result set, this result set will be inserted to a temporary table in another stored procedure.
This is my sample code.
CREATE OR REPLACE PROCEDURE get_account_list
(
type_id in account_type.account_type_id%type,
acc_list out sys_refcursor
)
is
begin
open acc_list for
select account_id, account_name, balance
from account
where account_type_id = type_id;
end get_account_list;
CREATE OR REPLACE PROCEDURE proc1
(
...
)
is
accounts sys_refcursor;
begin
get_account_list(1, accounts);
--How to bulk insert data in accounts to a temporary table?
end proc1;
In SQL Server, I can write as code below
CREATE PROCEDURE get_account_list
type_id int
as
select account_id, account_name, balance
from account
where account_type_id = type_id;
CREATE PROCEDURE proc1
(
...
)
as
...
insert into #tmp_data(account_id, account_name, balance)
exec get_account_list 1
How can I write similar to the code in SQL Server? Thanks.
you can use BULK operations on REF CURSOR:
SQL> CREATE GLOBAL TEMPORARY TABLE gt (ID NUMBER);
Table crÚÚe.
SQL> DECLARE
2 l_refcursor SYS_REFCURSOR;
3 TYPE tab_number IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
4 l_data tab_number;
5 BEGIN
6 OPEN l_refcursor FOR
7 SELECT ROWNUM FROM dual CONNECT BY LEVEL <= 1e6;
8 LOOP
9 FETCH l_refcursor BULK COLLECT
10 INTO l_data LIMIT 100;
11
12 FORALL i IN 1..l_data.count
13 INSERT INTO gt VALUES (l_data(i));
14
15 EXIT WHEN l_refcursor%NOTFOUND;
16
17 END LOOP;
18 CLOSE l_refcursor;
19 END;
20 /
ProcÚdure PL/SQL terminÚe avec succÞs.
Oracle 10g already implements this optimization for regular loop though, so you may not see much improvement from a simple LOOP...INSERT.
How about
procedure insert_rec(in_type_id in number) is
begin
insert into temp_table
select account_id, account_name, balance
from account
where account_type_id = in_type_id;
end insert_rec;