Snowflake SQL Procedure and Cursor - sql

I am working on a SQL procedure to read data from cursor and insert into table. How do i reference the cursor values in insert statement.
Below is what i have tried:
CREATE OR REPLACE PROCEDURE SP_FACT_SALES()
returns varchar(100)
LANGUAGE SQL
EXECUTE AS OWNER
AS '
declare
INVOICE_NUMBER varchar(15);
CUSTOMER VARCHAR(20);
AMOUNT NUMBER(17,2);
c1 cursor for select INVOICE_NUMBER,CUSTOMER,AMOUNT from db.schema.v_fact_sales limit 3;
begin
open c1;
fetch c1 into INVOICE_NUMBER,CUSTOMER,AMOUNT ;
insert into db.schema.fact_sales(INVOICE_NUMBER,CUSTOMER,AMOUNT)
values(c1.INVOICE_NUMBER,c1.CUSTOMER,c1.AMOUNT)
end ;
';
I am getting below error:
Uncaught exception of type 'STATEMENT_ERROR' on line 14 at position 1 : SQL compilation error: error line 2 at position 11 invalid identifier 'C1.INVOICE_NUMBER'
Do i have to FOR loop to reference cursor values or is there so way to bulk collect(similar to Oracle)
Any help would be appreciated!

You need to use a FOR loop to iterate through the cursor: https://docs.snowflake.com/en/sql-reference/snowflake-scripting/for.html

Related

I want to get count for rows in cursor in DB2

CREATE OR REPLACE PROCEDURE USP_TEST_ROW_COUNT(
OUT vROW_COUNT BIGINT
)
RESULT SETS 1
MODIFIES SQL DATA
LANGUAGE SQL
P1: BEGIN ATOMIC
BEGIN
DECLARE C1 CURSOR WITH RETURN FOR
SELECT * FROM TABLE_NAME;
OPEN C1;
SET vROW_COUNT = CURSOR_ROWCOUNT(C1);
END;
END P1
Above is my code but it is showing Below Error
DB2 SQL error: SQLCODE: -206, SQLSTATE: 42703, SQLERRMC: C1
Message: "C1" is not valid in the context where it is used.
Line: 12
Please Help.
You may insert the results into some DGTT if you want to return all rows in the result set and return the number of output rows simultaneously:
CREATE OR REPLACE PROCEDURE USP_TEST_ROW_COUNT(OUT vROW_COUNT BIGINT)
RESULT SETS 1
MODIFIES SQL DATA
BEGIN ATOMIC
DECLARE v_stab VARCHAR(100) DEFAULT 'SESSION.USP_TEST_ROW_COUNT';
DECLARE v_stmt VARCHAR(100) DEFAULT 'SELECT * FROM TABLE_NAME';
DECLARE C1 CURSOR WITH RETURN FOR S1;
EXECUTE IMMEDIATE
'DECLARE GLOBAL TEMPORARY TABLE '||v_stab||' AS ('
||v_stmt
||' ) DEFINITION ONLY WITH REPLACE ON COMMIT PRESERVE ROWS NOT LOGGED';
EXECUTE IMMEDIATE 'INSERT INTO '||v_stab||' '||v_stmt;
GET DIAGNOSTICS vROW_COUNT=ROW_COUNT;
PREPARE S1 FROM 'SELECT * FROM '||v_stab;
OPEN C1;
END#
CURSOR_ROWCOUNT can only return the number of rows fetched (by the caller of the stored procedure). This is different from the number of rows in the result set. So if your syntax was accepted the value would be zero initially as nothing as yet been fetched.
You can see an example here, which shows the cursor variable, the cursor being opened and fetched, and the resulting value returned by CURSOR_ROWCOUNT.
To find the number of rows in the result-set either consume the cursor (fetch until no more rows), or do a second query that counts the rows in the same unit of work, or append the count to each row and fetch only 1 row.

Getting an error "record type has not been registered" in postgresql. What is wrong?

CREATE OR REPLACE FUNCTION get_biggest_order()
RETURNS TABLE(CustomerID int,Sum float) AS
$$
DECLARE
rec RECORD;
mycursor CURSOR FOR WITH TOTAL(TotalPerCustomer) AS (SELECT SUM(TotalDue) FROM SalesOrderHeader GROUP BY SalesOrderHeader.CustomerID),
MAX(Max) AS (SELECT MAX(TotalPerCustomer) FROM TOTAL)
SELECT SalesOrderHeader.CustomerID,SUM(TotalDue) AS S FROM SalesOrderHeader,MAX GROUP BY SalesOrderHeader.CustomerID,Max HAVING SUM(TotalDue)=Max;
BEGIN
CREATE TEMP TABLE Results2(CustomerID int,Sum float);
-- Open the cursor
OPEN mycursor;
LOOP
-- fetch row into the film
FETCH mycursor INTO rec;
-- exit when no more row to fetch
EXIT WHEN NOT FOUND;
-- build the output
INSERT INTO Results2 SELECT (rec).*;
END LOOP;
-- Close the cursor
CLOSE mycursor;
RETURN QUERY EXECUTE 'SELECT * FROM Results2';
END; $$
LANGUAGE plpgsql;
SELECT get_biggest_order();
Getting the following error in Postgres:
ERROR: record type has not been registered
CONTEXT: SQL statement "INSERT INTO Results2 SELECT (rec).*"
PL/pgSQL function get_biggest_order() line 17 at SQL statement
********** Error **********
ERROR: record type has not been registered
SQL state: 42809
Context: SQL statement "INSERT INTO Results2 SELECT (rec).*"
PL/pgSQL function get_biggest_order() line 17 at SQL statement
I am trying to return the query within the cursor in table format using the cursor. Apparently something is wrong with the record type variable and it cannot insert it into the temp table which i want to return using the function. What is wrong?
rec is an untyped record, so replace SELECT (rec).* with VALUES (rec.CustomerID, rec.S).

DB2 dynamic table name

I want to count the rows of a number of tables. But the table name should be used dynamically. I want to do that within one SQL statement.
I tried it with
BEGIN ATOMIC
FOR tmp AS (
SELECT tabschema || '.' || tabname tbl
FROM syscat.tables WHERE tabname LIKE '%CD') DO
(SELECT COUNT(*) FROM tmp.tbl);
END FOR;
END
but I receive the error
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0204N "TMP.TBL" is an undefined name. LINE NUMBER=1. SQLSTATE=42704
and found no other working solution...
Is there a solution for that?
Thanks in advance.
I assume that your SELECT COUNT(*) FROM tmp.tbl should translate in multiple statements like
select count(*) from TABLECD
select count(*) from TABLE2CD
...
However, your query will try to do a count of the table TBL in the schema TMP.
You'll have to prepare the complete SQL statement, store it in a variable and pass it to the PREPARE statement (documentation ).
A rather complete stored procedure which somewhat fits your requirements can be found here . The result of the counts will be stored in a table COUNTERS which you can query afterwards.
//edit: this is the example from the topic, adapt to work (not tested since I have no DB2 instance to test atm):
CREATE PROCEDURE tableCount()
LANGUAGE SQL
BEGIN
DECLARE SQLCODE INTEGER DEFAULT 0;
DECLARE SQLSTATE CHAR(5);
DECLARE vTableName VARCHAR(20);
DECLARE vTableCount INTEGER;
DECLARE stmt varchar(2000);
DECLARE not_found CONDITION FOR SQLSTATE '02000';
DECLARE c1 CURSOR FOR
SELECT tabname from syscat.tables where tabschema='DB2ADMIN';
DECLARE C2 CURSOR FOR S2
DECLARE CONTINUE HANDLER FOR not_found
SET stmt = '';
Delete from COUNTERS;
OPEN c1;
getRows:
LOOP
FETCH c1 INTO vTableName;
IF SQLCODE = 0 THEN
SET stmt ='SELECT Count(*) FROM ' || vTableName;
PREPARE S2 FROM stmt;
OPEN C2;
SET vTableCount = 0;
FETCH C2 INTO vTableCount;
INSERT INTO COUNTERS (tableName, tableCount)
VALUES (vTableName, vTableCount);
CLOSE C2;
ELSE
LEAVE getRows;
END IF;
END LOOP getRows;
CLOSE c1;
END

How to create a Trigger in oracle?

I have oracle database 11gR2 and i want to create some triggers automatically with a block .
when i want to run query in below , i have an error .
My block is :
declare
tablesid number ;
tablenames varchar2(4000);
cursor c1 is
select id , title from hr.tables;
begin
open c1;
loop
fetch c1 into tablesid , tablenames;
CREATE OR REPLACE TRIGGER tablenames||'_before_insert'
before insert
on hr.tablenames
DECLARE
columnid number ;
columnval number ;
columntitle varchar(4000);
cursor c2 is
select id from hr.columns where tableid = tablesid ;
BEGIN
-- open c2 ;
for rec in c2 loop
select title into columntitle from hr.columns where id = rec.id
insert into hr.rowaction(columnid,newvalue,oldvalue,actiondate)
(
select id ,:new.columntitle,:old.columntitle,sysdate
from hr.tabletiltes
where id = rec.id
)
select title into columntitle from hr.columns where id = rec.id;
dbms_output.put_line(columntitle);
end loop;
end;
end loop ;close c1; end;
ORA-06550: line 11, column 6:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
( begin case declare end exit for goto if loop mod null
pragma raise return select update while with
<<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action :
Bind Variable "new" is NOT DECLARED
anonymous block completed
Bind Variable "new" is NOT DECLARED
anonymous block completed
Thanks
A trigger is a standalone separate piece of code that is usually considered DDL, the language that defines metadata for objects.
You cannot have a trigger declaration embedded inside a PL/SQL block. IF you need to CREATE some PL/SQL code on the fly - not a great idea - consider the DMBS_DDL.CREATE_WRAPPED procedure. You seem to have EXECUTE IMMEDIATE in mind as well. If so, have a read on this: (http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_ddl.htm)
You should define your trigger BEFORE running your PL/SQL in other words. Make two scripts.

How to insert into a table using stored procedures in DB2 using SQL?

I wanted to know how to insert into a table using stored procedures in DB2 using SQL.
I have created a table as follows:
create table ADCLIBT.Itest
(ITNBR CHAR(15) CCSID 65535 NOT NULL DEFAULT '');
This table contains a list of items. Using this list I want to insert various other fields to another table. But, just for example sake, let's say I just want to insert these values one by one using cursors.
I have written the stored procedure as follows:
create procedure ADCLIBT.itest1()
LANGUAGE SQL
BEGIN
DECLARE itemno char(15);
DECLARE END_TABLE INT DEFAULT 0;
DECLARE not_found CONDITION FOR SQLSTATE '20000';
DECLARE c CURSOR FOR
select ITNBR from ADCLIBT.ITEMAT;
DECLARE CONTINUE HANDLER FOR not_found
SET END_TABLE = 1;
open c;
fetch from c into itemno;
WHILE END_TABLE = 0 DO
insert into ADCLIBT.ITEST
(ITNBR)
values
(select a.ITNBR from ADCLIBT.ITEMAT a where ITNBR=itemno GROUP BY a.ITNBR);
END WHILE;
Close c;
END;
This is giving me an infinite loop. Can anyone please tell me how do I stop the infinite loop and insert these records. I want to use the cursor because I want to further use itemno to compare and get single results.
You are opening the cursor but not feching in the while, you must do a fetch in the while of the cursor. Here an example from the IBM documentation.
CREATE PROCEDURE sum_salaries(OUT sum INTEGER) LANGUAGE SQL
BEGIN
DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
DECLARE p_sum INTEGER;
DECLARE p_sal INTEGER;
DECLARE c CURSOR FOR SELECT SALARY FROM EMPLOYEE;
SET p_sum = 0;
OPEN c;
FETCH FROM c INTO p_sal;
WHILE(SQLSTATE = '00000') DO
SET p_sum = p_sum + p_sal;
FETCH FROM c INTO p_sal;
END WHILE;
CLOSE c;
SET sum = p_sum;
END%