Compilation error when declaring variables in BEGIN..END procedure PL/SQL - database

I have a compile error that unable to declare variables in procedure PL/SQL which trying solutions from other sources. Can anybody help to check what is the problem?
CREATE OR REPLACE PROCEDURE add_vaccine
(p_id IN VARCHAR, d_id IN VARCHAR, p_vdate IN DATE, p_vaccinated IN VARCHAR)
AS
BEGIN
DECLARE counter NUMBER(MAX);
--Prompt user to input vaccination and visit detail
DBMS_OUTPUT.PUT_LINE('Patient ID = ' || p_id);
DBMS_OUTPUT.PUT_LINE('Doctor ID = ' || d_id);
DBMS_OUTPUT.PUT_LINE('Date = ' || p_vdate);
DBMS_OUTPUT.PUT_LINE('Vaccinated = ' || p_vaccinated);
END;
/
The code is unfinished but I'm stuck at the variable declaration.

Whenever you have a DECLARE section, you must have a BEGIN and END with some code.
If you don't need to declare inside, you can always declare them after AS.
CREATE OR REPLACE PROCEDURE STH()
AS
<DECLARE VARIABLES HERE>
BEGIN
DECLARE
<YOU CAN DECLARE HERE AS WELL>
BEGIN
DBMS_OUTPUT.PUT_LINE('HELLO');
END;
-- Do something here
END;

There is an implict DECLARE before the first BEGIN in your procedure hence
SQL> CREATE OR REPLACE PROCEDURE add_vaccine
2 (p_id IN VARCHAR, d_id IN VARCHAR, p_vdate IN DATE, p_vaccinated IN VARCHAR)
3 AS
4
5 counter NUMBER;
6 BEGIN
7 --Prompt user to input vaccination and visit detail
8 DBMS_OUTPUT.PUT_LINE('Patient ID = ' || p_id);
9 DBMS_OUTPUT.PUT_LINE('Doctor ID = ' || d_id);
10 DBMS_OUTPUT.PUT_LINE('Date = ' || p_vdate);
11 DBMS_OUTPUT.PUT_LINE('Vaccinated = ' || p_vaccinated);
12 END;
13 /
Procedure created.

Related

Calling a procedure inside a procedure with independent sessions

I am trying to call a procedure inside a procedure but this gives me an error like:
Uncaught exception of type 'STATEMENT_ERROR' on line 19 at position 2 : This session warehouse WH_STD_EDWQA_ANALYST no longer exists.
My parent procedure construct is like creating a warehouse & the child procedure is to populate a metadata table(custom) by use of table(result_scan(last_query_id())).
Parent procedure construct:
create or replace procedure wh_resource_govern(type varchar, env varchar, ..., varchar)
returns varchar not null
language sql
as
$$
declare
wh_name varchar;
wh_setup varchar;
lv_acct_name varchar;
begin
wh_name := 'WH_' || type || '_' || env || '_' || team;
wh_setup := 'CREATE OR REPLACE WAREHOUSE' || ' ' || wh_name || ' ' || 'WITH' || ' '
|| 'WAREHOUSE_SIZE = ' || v_wh_size || ' '
...,
|| 'COMMENT= '|| '"' || v_created_by || '"' ;
execute immediate wh_setup;
commit;
call load_all_warehouse_metadata('a', 'b', 'c'); ----> This is where it is getting stuck.
end;
$$
;
Child procedure construct is given as below:
create or replace procedure load_all_warehouse_metadata(wh_type varchar, wh_env varchar, wh_team varchar)
returns varchar not null
language sql
as
$$
declare
lv_acct_name varchar;
begin
select current_account() into lv_acct_name;
show warehouses;
insert into ALL_WAREHOUSE_METADATA (account_name, warehouse_type, .., .., )
select :lv_acct_name, :wh_type, :wh_env, :wh_team, "name", ..., ...,
from table(result_scan(last_query_id()));
end;
$$
;
Any inputs on how to address this would be really helpful.
Creating a warehouse immediately makes it the current warehouse for the session, example:
create or replace warehouse FOO;
select current_warehouse(); -- FOO
drop warehouse FOO();
select current_warehouse(); -- NULL
When you run execute immediate wh_setup; in the first SP, it's setting the session's warehouse to the one you just created. Calling a child SP using owner's rights (default) from a warehouse that isn't the one that started the SP is causing context problems for the warehouse.
You can reproduce this error as follows:
create or replace procedure SP1()
returns varchar not null
language sql
--execute as caller
as
$$
declare
currentWarehouse varchar;
begin
select current_warehouse() into currentWarehouse;
create or replace warehouse FOO;
call SP2();
return currentWarehouse;
end;
$$;
create or replace procedure SP2()
returns varchar not null
language sql
--execute as caller
as
$$
declare
currentWarehouse varchar;
begin
select current_warehouse() into currentWarehouse;
create or replace temp table FOO(s string);
insert into FOO(S) values ('Bar');
return 'Done';
end;
$$;
call SP1();
You can fix this code sample immediately by uncommenting the two commented-out ownership options for SP1 and SP2:
--execute as caller (Remove the comment markers and recreate both SPs.)
You can also run a SQL command to use warehouse <wh_name> in your SP(s), but you must run the SP as caller in order to change warehouse context this way.

Range partitioning tables with data in DB2 LUW

First of all my question will be, if there is a way of auto-generation partitions (like interval in Oracle for range partitioning) while inserting data into the partitioned table in DB2?
At the moment I have a schema with some hundreds of tables, which are not partitioned. And I suppose to partition them.
My steps will be:
rename all the tables to OLD_table_name
execute DDLs for those tables but already partitioned (by load_id column int data type)
execute for all, insert into table_name select * from OLD_table_name
...and here it starts.
(Of course the process must be automatically and I don't know which values contain load_id column + they will be all different for all the tables, otherwise it would be possible to generate simply alter statements and execute them).
Therefore I would go for cursor.
For the moment I have solution which is working but I don't like it:
BEGIN
FOR CL AS MYCURS INSENSITIVE CURSOR FOR
select distinct 'alter table '||tb_nm||'
add partition PART_'||lpad(load_id,5,0)||'
starting from '||load_id||'
ending at '||load_id v_alt
from (
select load_id,'Table_01' tb_nm from Table_01
union
select load_id ,'Table_02'from Table_02
union
....
/*I have generated this union statements for whole set of tables*/)
do
execute immediate v_alt;
end for;
end
Also, I have tried some more elegant (on my opinion) variant, but didn't sucseed:
BEGIN
DECLARE v_stmnt VARCHAR(1000);
DECLARE v_check_val int;
DECLARE v_prep_stmnt STATEMENT;
for i as (select table_name
from sysibm.tables
where TABLE_SCHEMA ='shema_name'
)
do
SET v_stmnt = 'set ? = (SELECT distinct(load_id) FROM '||table_name||')';
PREPARE v_prep_stmnt FROM v_stmnt;
/*and here I stuck. I assume there must be possibility to run next execute as well in loop, but
all my attempts were not succsesfull*/
--EXECUTE v_prep_stmnt into v_check_val ;
end for;
END
Would highly appreciate any hint.
Try something like this:
--#SET TERMINATOR #
SET SERVEROUTPUT ON#
BEGIN
DECLARE L_TABSCHEMA VARCHAR(128) DEFAULT 'SCHEMA_NAME';
DECLARE L_COLNAME VARCHAR(128) DEFAULT 'LOAD_ID';
DECLARE L_VALUE INT;
DECLARE L_STMT VARCHAR(1024);
DECLARE SQLSTATE CHAR(5);
DECLARE C1 CURSOR FOR S1;
FOR I AS
SELECT TABNAME
FROM SYSCAT.COLUMNS
WHERE TABSCHEMA = L_TABSCHEMA AND COLNAME = L_COLNAME
DO
PREPARE S1 FROM 'SELECT DISTINCT(' || L_COLNAME || ') FROM ' || L_TABSCHEMA || '."' || I.TABNAME ||'"';
OPEN C1;
L1: LOOP
FETCH C1 INTO L_VALUE;
IF SQLSTATE<>'00000' THEN LEAVE L1; END IF;
SET L_STMT =
'alter table ' || L_TABSCHEMA || '."' || I.TABNAME || '" '
||'add partition PART_' || lpad(L_VALUE, 5, 0) || ' starting from ' || L_VALUE || ' ending at ' || L_VALUE;
--CALL DBMS_OUTPUT.PUT_LINE(L_STMT);
EXECUTE IMMEDIATE L_STMT;
END LOOP;
CLOSE C1;
END FOR;
END
#

Update a table with the result of a store procedure actions over a column from the table

I have a table name resultado, that is created by calling and executing another stored procedures or functions. As a result a have a column that contains '1' and '0' as a vector like this '111100001'. Also I have a store procedured that count the numbers of 1 in the 'vector' as it follows.
ALTER PROC [dbo].[CharCount](#String VARCHAR(4000),#caracter VARCHAR(2))
AS
BEGIN
DECLARE #long INT
DECLARE #numeroveces INT =0
DECLARE #consecutivo INT =0
DECLARE #consecutivo1 INT =0
SET #numeroveces=0
SET #long=LEN(#String)
WHILE #long>=0
BEGIN
IF #caracter=SUBSTRING(#String,#long,1)
BEGIN
set #numeroveces = #numeroveces + 1
set #consecutivo = #consecutivo + 1
END
IF #caracter<>SUBSTRING(#String,#long,1) or (#long = 0)
BEGIN
IF #consecutivo > #consecutivo1
BEGIN
set #consecutivo1 = #consecutivo
END
set #consecutivo = 0
END
SET #long=#long-1
END
SELECT #numeroveces
SELECT #consecutivo1
END
What I need is to execute the store procedure over a column from my table resultado and update the column with the result of the SP.
OriginalColumn--->SPResult---->UpdatedColumn
110111 ---> 5 ----> 5
Your procedure has 2 result sets the way you have it coded. Since in the example you posted here you are only trying to get the count of a given character I would strongly advise you to not use this procedure. It is horribly inefficient for such a simple task. This simple code will get the number of occurrences of a character without doing any looping. If you also need the longest consecutive count of occurrences there are better ways to do that too.
declare #String varchar(4000) = '111100001'
, #caracter VARCHAR(2) = '1'
select LEN(#String) - LEN(Replace(#String, #caracter, ''))

Netezza/SQL Column Alias concatenate text with parameter value

In the stored procedure below, I simply want to create a column alias based on a parameter value. It looks simple, but I could not find my answer.
CREATE OR REPLACE PROCEDURE "SP"(INTEGER, INTEGER)
RETURNS INTEGER
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
whichyear ALIAS FOR $1;
BEGIN
Select x as "Some Text" + whichyear from some table...
;
END;
END_PROC;
Tab is right that this would require dynamic SQL in Netezza. Here is an example.
CREATE OR REPLACE PROCEDURE "SP"(INTEGER)
RETURNS INTEGER
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
whichyear ALIAS FOR $1;
vSQL varchar(30000);
BEGIN
drop table the_results if exists;
vSQL := 'CREATE TABLE THE_RESULTS AS SELECT COL1 "SOME TEXT ' || whichyear || '" FROM TABLE_A;';
execute immediate vSQL;
END;
END_PROC;
Here's the output.
TESTDB.ADMIN(ADMIN)=> exec SP(5);
SP
----
(1 row)
TESTDB.ADMIN(ADMIN)=> select * from the_results;
SOME TEXT 5
-------------
2
3
1
(3 rows)
In SQL Server, you would use dynamic sql like this:
DECLARE #sql varchar(max) = 'Select x as SomeText' + #whichyear + ' from sometable';
EXEC(#sql);

Add a column, with a derived column name, to an existing table in SQL Server 2014

DECLARE
#countFlag INT,
#maxNum INT = 5,
#addingName NVARCHAR(6)
SET #countFlag = 1
WHILE (#countFlag <= #maxNum)
BEGIN
SET #addingName = 'name' + CAST(#countFlag AS NVARCHAR(2))
ALTER TABLE TableName
ADD
#addingName NVARCHAR(30)
SET #countFlag = #countFlag + 1
END
========================================================
This is called at the beginning of a set of procedures. #maxNum is actually passed in based on a question to the operator and changes the 'shape' of an existing db to include more columns. I would like to have the resulting column names be something like "name1" "name2" etc. but I am getting an "Incorrect syntax near '#addingName'" after the ADD statement when I execute it. What am I doing wrong here?
You cannot do it in that way, you should compose the query dynamically and execute it with Exec:
DECLARE #sqlCommand varchar(200)
SET #sqlCommand = 'ALTER TABLE TableName ADD ' + #addingName + ' NVARCHAR(30) '
EXEC (#sqlCommand)

Resources