I am trying to develop web application based on tutorial example. I have created procedure cilveki_list which has many parameters. When I compile this code I get two errors:
1)PL/SQL: SQL Statement ignored
2)PL/SQL: ORA-00933: SQL command not properly ended
First error refers to line 'c_kods in varchar2 default null'
and the second one to line ' if p_action = 'INSERT' then'.
Proedure behaviour depends on the parameter 'p_action', if it is set to 'INSERT', then insertion is perfomed, if it is set to 'UPDATE', then table update is performed.
But what is wrong with porcedue, why I get those errors, when I try to compile it?
create or replace package PACKAGE2 is
procedure cilveki_list(
c_vards in char default null,
c_uzvards in char default null,
c_dzimsanas_gads in number default null,
c_kods in varchar2 default null,
p_action in varchar2 default 'DISPLAY');
end PACKAGE2;
/
create or replace package body PACKAGE2 is
procedure cilveki_list(
c_vards in char default null,
c_uzvards in char default null,
c_dzimsanas_gads in number default null,
c_kods in varchar2 default null,
p_action in varchar2 default 'DISPLAY')
is
l_count number := 0;
begin
if p_action = 'INSERT' then
insert into CILVEKI
values ('',c_vards,c_uzvards,c_dzimsanas_gads,c_kods);
commit;
elsif p_action = 'UPDATE' then
UPDATE CILVEKI
set VARDS = c_vards,
UZVARDS = c_uzvards,
DZIMSANAS_GADS = c_dzimsanas_gads
WHERE PERS_KODS = c_kods;
commit;
end if;
htp.htmlOpen;
htp.bodyOpen;
htp.tableOpen;
htp.tableRowOpen;
htp.tableHeader('VARDS');
htp.tableHeader('UZVARDS');
htp.tableHeader('DZIMSANAS_GADS');
htp.tableHeader('PERS_KODS');
htp.tableRowClose;
for c1 in (select VARDS, UZVARDS, DZIMSANAS_GADS,PERS_KODS
from CILVEKI
order by UZVARDS) loop
htp.tableRowOpen;
htp.tableData(
htf.anchor(
curl => 'cilveki_modify?p_action=UPDATE&p_ticker=' || c1.VARDS,
ctext => c1.VARDS) );
htp.tableData( c1.UZVARDS );
htp.tableData( c1.DZIMSANAS_GADS );
htp.tableData( c1.PERS_KODS );
htp.tableRowClose;
l_count := l_count + 1;
end loop;
htp.tableClose;
htp.p( l_count || ' rows found');
htp.anchor( curl => 'cilveki_modify?p_action=INSERT',
ctext => 'Create New' );
htp.bodyClose;
htp.htmlClose;
end cilveki_list;
end PACKAGE2;
/
UPDATE CILVEKI
set VARDS = c_vards,
UZVARDS = c_uzvards,
DZIMSANAS_GADS = c_dzimsanas_gads,
WHERE PERS_KODS = c_kods
commit;
4th line above appears to be invalid. There shouldn't be a comma at the end of the line. Please remove the comma and re-compile the code.
Related
I started writing this stored procedure and I faced some issues when I try to pass a variable in my conditional statement.
I can use the parameter BANKN which works fine, but when never I passed the declared variable AC_t somehow the PL/SQL ignores it.
Any idea please what I'm missing here?
create or replace PROCEDURE TTEST1 (
CR IN VARCHAR2,
BANKN IN VARCHAR2,
P_CURSOR OUT SYS_REFCURSOR
)
AS
G_AC CHAR(10);
AC_t Billing.Account %Type;
BEGIN
IF BANKN = 'WLNV' AND AC_t = 'Private'
THEN
IF CR IN (
'EUR',
'CZK',
'USD'
)
THEN
OPEN P_CURSOR
FOR
SELECT G_AC AS GL_ACC,
Billing.Account AS ACC_Type
INTO
G_AC,
AC_t
FROM Billing
INNER JOIN invoice ON Billing.ACC_NO = invoice.ACC_NO;
END IF ;
END IF ;
END;
My aim here is to expand this code by using AC_t value from Billing.ACCount and retrieve what ever data that can be 'Private' or 'Public'.
To do this, I need to use case or IF statement, however when I use
Billing.ACCount, I got an error "not allowed in this context", for this reason I use synonym AC_t but this don't read values from Billing table unless I use it in WHERE clause.
ACC_NO
Account
1
Private
2
Public
Extended code:
IF BANKN = 'WLNV' AND AC_t = 'Private'
THEN
...
...
ELSIF IF BANKN = 'WLNV' AND AC_t = 'Public'
THEN
....
...
You cannot use SELECT ... INTO with a cursor and you need to declare a value for the ac_t variable (but since it is a column in the table you may want a WHERE clause in the cursor). Like this:
CREATE PROCEDURE TTEST1 (
p_CR IN VARCHAR2,
p_BANKN IN VARCHAR2,
P_CURSOR OUT SYS_REFCURSOR
)
AS
BEGIN
IF p_BANKN = 'WLNV'
AND p_CR IN ( 'EUR', 'CZK', 'USD' )
THEN
OPEN P_CURSOR FOR
SELECT G_AC AS GL_ACC,
b.account AS ACC_Type
FROM Billing b
INNER JOIN invoice i
ON b.ACC_NO = i.ACC_NO
WHERE b.account = 'Private';
END IF;
END;
/
Which, if you have the sample data:
CREATE TABLE invoice (acc_no, g_AC) AS
SELECT 1, 2 FROM DUAL;
CREATE TABLE billing (acc_no, account) AS
SELECT 1, 'Private' FROM DUAL;
Then you can call the procedure and print the contents of the cursor using:
DECLARE
cur SYS_REFCURSOR;
v_g_ac INVOICE.G_AC%TYPE;
v_ac_t BILLING.ACCOUNT%TYPE;
BEGIN
ttest1('EUR', 'WLNV', cur);
LOOP
FETCH cur INTO v_g_ac, v_ac_t;
EXIT WHEN cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( v_g_ac || ', ' || v_ac_t );
END LOOP;
CLOSE cur;
END;
/
Which outputs:
2, Private
db<>fiddle here
I am trying to get around a problem where the following SP locks the log table DWH_METADATA.LOG_TABLE and the lock is released only when the DELETE ALL and INSERT-SELECT statements are executed. This procedure chokes the whole ETL process. Moreover, this procedure is called via IBM Data Stage Sequence.
Below is the procedure code:
REPLACE PROCEDURE DWH.HIST_PROC (OUT RETURN_MSG VARCHAR(100))
BEGIN
/**********************************
* DECALRE VARIABLES *
**********************************/
DECLARE PJ_RID INTEGER;
DECLARE MS_Name VARCHAR(100);
DECLARE JS_Name VARCHAR(100);
DECLARE JT_Name VARCHAR(100);
DECLARE PJ_Domain VARCHAR(100);
DECLARE JS_Timestamp TIMESTAMP(0);
DECLARE Script_Name VARCHAR(500);
DECLARE Procedure_Name VARCHAR(100);
DECLARE JS_No INTEGER;
DECLARE SS_Ts TIMESTAMP(0);
DECLARE SR_Processed INTEGER;
/***********************************
* EXCEPTION HANDLING *
***********************************/
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
UPDATE DWH_METADATA.LOG_TABLE
SET
JOB_STATUS = SQLCODE,
STEP_END_TS = CURRENT_TIMESTAMP(0),
JOB_END_TIMESTAMP = CURRENT_TIMESTAMP(0)
WHERE JOB_RUN_ID = PJ_RID
AND STEP_NO = JS_No
AND JOB_NAME = JS_Name;
END;
/**********************************
* SET VARIABLES *
**********************************/
SET MS_Name = 'A Value';
SET JS_Name='A Value';
SET JT_Name = 'A Value';
SET PJ_Domain = 'A Value';
SET JS_Timestamp = CURRENT_TIMESTAMP(0);
SET Script_Name = 'A Value';
SET Procedure_Name = 'A Value';
SET SS_Ts = CURRENT_TIMESTAMP(0);
SET JS_No = 0;
SET RETURN_MSG = 'Failure';
--------------------------------------------------------
--Insert log for step 0
INSERT INTO DWH_METADATA.LOG_TABLE
(
DWH_METADATA.LOG_TABLE.JOB_RUN_ID,
DWH_METADATA.LOG_TABLE.STEP_NO,
DWH_METADATA.LOG_TABLE.MASTER_SEQ_NAME ,
DWH_METADATA.LOG_TABLE.JOB_NAME ,
DWH_METADATA.LOG_TABLE.TABLE_NAME,
DWH_METADATA.LOG_TABLE.JS_Timestamp ,
DWH_METADATA.LOG_TABLE.JOB_END_TIMESTAMP ,
DWH_METADATA.LOG_TABLE.SS_Ts ,
DWH_METADATA.LOG_TABLE.STEP_END_TS ,
DWH_METADATA.LOG_TABLE.JOB_STATUS ,
DWH_METADATA.LOG_TABLE.JOB_DOMAIN ,
DWH_METADATA.LOG_TABLE.SCRIPT_NAME ,
DWH_METADATA.LOG_TABLE.PROCEDURE_NAME ,
DWH_METADATA.LOG_TABLE.RECORDS_PROCESSED
)
VALUES
(:PJ_RID, :JS_No, :MS_Name, :JS_Name, :JT_Name,
:JS_Timestamp, NULL, :SS_Ts, NULL, NULL, :PJ_Domain, :Script_Name, :Procedure_Name, NULL
);
-----------------------------------------------------------------------------------------------------------------
LOCKING ROW FOR ACCESS
SEL COALESCE(MAX(JOB_RUN_ID),0) + 1
FROM DWH_METADATA.LOG_TABLE
WHERE JOB_NAME = :JS_Name
AND Job_Domain = :PJ_Domain
INTO :PJ_RID;
/********************************** DELETE/INSERT RTD_DATA *************************************************/
--Insert log for step 1
SET JS_No = JS_No + 1 ;
SET JT_Name = 'DWH.HISTORY_TABLE ';
SET SS_Ts = CURRENT_TIMESTAMP(0);
INSERT INTO DWH_METADATA.LOG_TABLE
VALUES( :PJ_RID, :JS_No, :MS_Name, :JS_Name, :JT_Name, :JS_Timestamp,
NULL, :SS_Ts, NULL, NULL, :PJ_Domain, :Script_Name, :Procedure_Name, NULL);
DELETE FROM DWH.HISTORY_TABLE ALL;
INSERT INTO DWH.HISTORY_TABLE
(
COLUMNLIST
)
SELECT
SI.COLUMNS,
S2.COLUMNS,
.
.
.
FROM SOMETABLE1 S1
INNER JOIN SOMETABLE2 S2
ON S1.ID = S2.ID
.
.
.
.;
--Update log for step 1
SET SR_Processed = ACTIVITY_COUNT;
UPDATE DWH_METADATA.LOG_TABLE
SET
JOB_STATUS = SQLCODE,
STEP_END_TS = CURRENT_TIMESTAMP(0),
JOB_END_TIMESTAMP = CURRENT_TIMESTAMP(0),
RECORDS_PROCESSED = :SR_Processed
WHERE JOB_RUN_ID = PJ_RID
AND STEP_NO = JS_No
AND JOB_DOMAIN = PJ_Domain
AND PROCEDURE_NAME = Procedure_Name
AND "TABLE_NAME"=JT_Name;
---------------------------------------------------------------------------------------
SET RETURN_MSG = 'Success' ;
END;
Based on same logic, many other stored procedures are executing on daily basis without any such issue. I am unable to understand, why this procedure locks the log table although both of its' insert statements have been executed.
I have tried to execute the individual DML statements in BT and ET, and doing such did not have any impact and the issue persisted. Moreover, I have optimized the underlying INSERT-SELECT. It has reduced the exeution time significantly but the locking is still occurring.
Anyone please, help me pinpoint why this issue is ocurring.
EDIT: Structure of log table.
CREATE MULTISET TABLE DWH_METADATA.LOG_TABLE ,FALLBACK ,
NO BEFORE JOURNAL,
NO AFTER JOURNAL,
CHECKSUM = DEFAULT,
DEFAULT MERGEBLOCKRATIO,
MAP = TD_MAP1
(
JOB_RUN_ID INTEGER,
STEP_NO INTEGER,
MASTER_SEQ_NAME VARCHAR(50) CHARACTER SET LATIN NOT CASESPECIFIC,
JOB_NAME VARCHAR(200) CHARACTER SET LATIN NOT CASESPECIFIC,
TABLE_NAME VARCHAR(50) CHARACTER SET LATIN NOT CASESPECIFIC,
JOB_START_TIMESTAMP TIMESTAMP(6),
JOB_END_TIMESTAMP TIMESTAMP(6),
STEP_START_TS TIMESTAMP(0),
STEP_END_TS TIMESTAMP(0),
JOB_STATUS INTEGER,
JOB_DOMAIN VARCHAR(200) CHARACTER SET LATIN NOT CASESPECIFIC,
SCRIPT_NAME VARCHAR(100) CHARACTER SET LATIN NOT CASESPECIFIC,
PROCEDURE_NAME VARCHAR(100) CHARACTER SET LATIN NOT CASESPECIFIC,
RECORDS_PROCESSED DECIMAL(18,0))
PRIMARY INDEX ( JOB_NAME ,TABLE_NAME ,JOB_START_TIMESTAMP );
I need to save a procedure body into a Clob column with a use of variable. String is longer than 4000 characters, so I can't use VarChar2, but with CLOB variable I receive error "ORA-01422: exact fetch returns more than requested number of rows". Same error appears with Varchar2. My PL/SQL block:
DECLARE
txt_procedure CLOB;
BEGIN
SELECT text INTO txt_procedure
FROM all_source
WHERE name = 'My_procedure'
ORDER BY line;
INSERT INTO TABLE1(ID,DATE,CLOB_COLUMN)
VALUES (my_seq.NEXTVAL,'11.10.2018',txt_procedure);
END;
/
How could I insert procedure body into clob column ?
As you will get multiple rows from your query for every line of your source, the following might help:
DECLARE
txt_procedure CLOB;
BEGIN
FOR source_r IN ( SELECT text
FROM all_source
WHERE name = 'My_procedure'
ORDER BY line
)
LOOP
txt_procedure := txt_procedure || chr(10) || source_r.text;
END LOOP;
INSERT INTO TABLE1(ID,DATE,CLOB_COLUMN)
VALUES (my_seq.NEXTVAL,'11.10.2018',txt_procedure);
END;
/
UPDATE
As an alternative, you might also use the DBMS_METADATA package for this:
DECLARE
txt_procedure CLOB;
BEGIN
txt_procedure := DBMS_METADATA.get_ddl(
object_type => 'PROCEDURE',
name => 'My_procedure',
owner => 'YOUR_SCHEMA'
);
INSERT INTO TABLE1(ID,DATE,CLOB_COLUMN)
VALUES (my_seq.NEXTVAL,'11.10.2018',txt_procedure);
END;
/
I am Wrting a Stored Function As below in db2.
CREATE OR replace FUNCTION moc_enddate( IN v_date VARCHAR(6),
IN v_message VARCHAR(20)) returns DATE
BEGIN
DECLARE v_temp DATE;
DECLARE v_end_date DATE;
DECLARE v_temp_string VARCHAR(8) DEFAULT '01';
SET v_temp_string = v_temp_string
|| v_date;
SET v_temp = to_date(v_temp_string,'DDMMYYYY');
SET v_end_date = (v_temp + 19 days);
RETURN v_end_date;
EXCEPTION
WHEN no_data_found THEN
SET v_message = 'SqlDataException';
WHEN OTHERS THEN
SET v_message = 'OTHER';
END;
But I am getting the following Exception.
ERROR [42601] [IBM][DB2/AIX64] SQL0104N An unexpected token "EXCEPTION" was found following "RN V_END_MOC_DATE; ". Expected tokens may include.
"<psm_case>".
Maybe, you are using DB2 SQL PL instead of PL/SQL. There is a difference between these languages. If it's the case, the following condition should work:
create or replace procedure CreatePlants
begin
declare sqlstate char(5) default '00000';
declare ErrorMsg varchar(96);
declare exit handler for sqlexception
begin
set ErrorMsg = 'SQLSTATE=' concat sqlstate;
signal sqlstate '99001'
set message_text = ErrorMsg;
end;
create table plants
( ID dec(3), Location varchar(16),
primary key (ID));
label on table plants is 'Plant master';
insert into plants values
( 1, 'Lost Angeles'),
( 2, 'New Yolk'),
( 3, 'Last Vegas');
end
For more references see:
Error Handling in SQL PL, Part 1
Determine The State Of The Error
I'm using TOAD for Oracle 11 and am pretty new to SQL. I have written a proc and am now trying to test and view its output. I have written the following block:
DECLARE
cur_test SYS_REFCURSOR;
type t_row is record(psh_code varchar2(20) , pattr_end_date varchar2(20), pperf_gross varchar2(20));
r_test t_row;
BEGIN
procPerfTR(xxx-xxxx', 'xxxxxxx', 'xxxxxxx', 'xxxxxx', :cur_test);
LOOP
FETCH cur_test INTO r_test;
EXIT WHEN cur_test%NOTFOUND;
END LOOP;
CLOSE cur_test;
END;
/
However, I get the following error on the LOOP line
ORA-01001: invalid cursor
The error is on line 10 which is the line that has "LOOP" on it
My proc looks like this
CREATE OR REPLACE PROCEDURE procPerfTR
(
paramPortfCode VARCHAR2,
paramEndDate VARCHAR2,
paramShare VARCHAR2,
paramFreq VARCHAR2,
O_cursorPerf out SYS_REFCURSOR
)
IS
I_cursorPerf SYS_REFCURSOR;
BEGIN
OPEN I_cursorPerf FOR
SELECT PS.PSH_CODE, PP.PATTR_END_DATE, PP.PPERF_GROSS
FROM
PORTFOLIO_PERFORMANCES PP
INNER JOIN PORTF_SHARE PS ON PS.PORTF_SHARE_ID = PP.PORTF_SHARE_ID
INNER JOIN PORTFOLIO P ON P.PORTF_ID = PS.PORTF_ID
INNER JOIN T_FREQUENCY TF ON TF.FREQUENCY_ID = PP.FREQUENCY_ID
WHERE
P.PORTF_CODE = paramPortfCode
AND PP.PATTR_CALCUL_DATE = PP.PATTR_END_DATE
AND PP.PATTR_END_DATE = paramEndDate
AND TF.EXT_CODE = paramFreq
AND PS.PSH_CODE LIKE
(CASE
WHEN paramShare = 'xxxx' THEN '%xxx'
WHEN paramShare = 'xxxx' THEN '%xxx'
END);
O_cursorPerf:=I_cursorPerf;
END;
/
In your proc invocation, don't put a colon in front of the name of the cursor. It should look like
procPerfTR('xxx-xxxx', 'xxxxxxx', 'xxxxxxx', 'xxxxxx', cur_test);
(Note also that I added a single-quote at the start of the first parameter, the absence of which I took to be a simple typo).
Share and enjoy.