I'm currently attempting to convert some code from Netezza code stored procedure to Snowflake stored procedure. There is one particular piece that I'm trying to convert by using a SQL cursor for loop.
The Netezza code is this
FOR counter IN 1 .. l_count LOOP
I was originally attempting to do in snowflake
let c1 cursor for counter;
FOR l_count in c1 do
And I also declared counter as counter RESULTSET;
Yet this doesn't seem to be working and I tried alternating it in many different ways but cannot seem to figure it out.
Snowflake also supports FOR LOOP:
CREATE OR REPLACE TABLE t(i INT);
DECLARE
l_counter INT := 5;
BEGIN
FOR counter IN 1 TO l_counter DO
INSERT INTO t(i) SELECT :counter;
END FOR;
END;
Output:
SELECT * FROM t;
--I
--1
--2
--3
--4
--5
Related
What data type can I use to store all rows found by SELECT query?
CREATE OR REPLACE PROCEDURE handleFailedCalls(xNumber in varchar(10)) AS
result {DATA TYPE I WANT};
BEGIN
select * into result
from CALLS c1
where c1.status = 'fail'
END
/
One way is to use a REFCURSOR variable of OUT type.
CREATE OR REPLACE PROCEDURE handleFailedCalls(xNumber in varchar2,
p_result OUT SYS_REFCURSOR
) AS
BEGIN
OPEN p_result FOR select * from CALLS c1
where c1.status = 'fail'
END
/
Also, use VARCHAR2 instead of VARCHAR. It should be without the size, as procedure arguments with size won't compile.
The procedure can be called to receive the cursor into a local ref cursor variable.
DECLARE
res_cur SYS_REFCURSOR;
BEGIN
handleFailedCalls('Xnumber1', res_cur );
END;
/
Use BULK COLLECT, example:
DECLARE
TYPE emp_typ IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER;
all_employees emp_typ;
BEGIN
SELECT * BULK COLLECT INTO all_employees FROM employees;
A SELECT ... BULK COLLECT INTO statement can return multiple rows. You must set up collection variables to hold the results. You can declare associative arrays or nested tables that grow as needed to hold the entire result set.
table :
create table emp
(
E_ID number,
E_NAME varchar2(30)
);
select * from emp;
101 name1
102 name2
My code:
declare
v1 varchar2(30) := '101,102';
begin
for i in (select e_id,e_name
from emp
where e_id in (v1)) loop
dbms_output.put_line(i.e_id);
end loop;
end;
/
ISSUE:
Getting ORA -01722:invalid number
Please help to understand this issue and suggest me the solution.
It is syntax error.
E_ID is of number type and you are comparing it will v1 which is varchar2 type.
Welcome to SO. A great place to ask questions: I can see what you're trying to do. Syntactically, you'd be forgiven for trying to query your table using the "IN" clause, but as others have said, this can not be done where you have committed your numeric values into a varchar2. In anycase, an array or a collection, (even if you had created one) it isn't an easy option here. But you do have a variety of solutions open to you:
1/ Place your numbers into an Array and use a condition in your loop and check that e_id forms part of the your array. But in-elegant!
2/ Create a global temporary table and add your numbers in and add the table into your query, specify a join.
3/ Create some dynamic PL/SQL using a Ref Cursor. I've included an example for you below, using your table (emp) and values. In this case, you'd be able to build up your string according to the values you want to query. See below. The varchar2 string: sqlString can be manipulated however you want. Paste into a test-harness and see. Hope it helps
declare
type refCursor is ref cursor;
tableCursor refCursor;
emp_record emp%rowtype;
sqlString varchar2(200);
begin
-- Dynamic SQL statement with placeholder:
sqlString := 'SELECT * FROM emp WHERE e_id in
(101, 102)';
-- Open cursor:
open tableCursor for sqlString;
-- Fetch rows from result set one at a time:
loop
fetch tableCursor
into emp;
exit when tableCursor%notfound;
dbms_output.put_line(emp.e_id);
end loop;
-- Close cursor:
close tableCursor;
end;
I used oracle
I want to declare a procedure that allows me to make insertion in a table
I try with this code without success
CREATE OR REPLACE PROCEDURE ADDSTEP(nbrStep character varying)
is
i integer :=0;
BEGIN
FOR i IN 0..nbrStep LOOP
INSERT INTO mytabletest
VALUES (i);
END LOOP;
END;
I have this error :
PROCEDURE ADDSTEP compiled
Errors: check compiler log
There are multiple issues with your code:
nbrStep character varying
There is no such data type called "character varying" in Oracle. For string you would use VARCHAR2. However, since you want to use it later in the loop for iteration, you need it to be NUMBER.
FOR i IN 0..nbrStep LOOP
You need to iterate from 1 till the boundary.
i integer :=0;
Not needed.
Modify the procedure as:
CREATE OR REPLACE PROCEDURE ADDSTEP(nbrStep NUMBER)
is
i integer :=0;
BEGIN
FOR i IN 0..nbrStep LOOP
INSERT INTO mytabletest
VALUES (i);
END LOOP;
END;
/
Anyway, you entire procedure could be done in a single INSERT SQL. It is called row generator method.
Try,
INSERT INTO mytabletest
SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 100;
Above, in place of 100, you could use the value of your choice which is the value you are passing as parameter **nbrStep ** in the above procedure.
Strange syntax of input variables. Corrected for Oracle -
CREATE OR REPLACE PROCEDURE addstep(nbrstep IN NUMBER)
IS
BEGIN
FOR i IN 0.. nbrstep
LOOP
INSERT INTO mytabletest
VALUES (i);
END LOOP;
END;
I am reading a lot of stuff about repeating Select statements within a loop but I am having some difficulties as I have not found something clear till now. I want to execute some queries (Select queries) several times, like in a FOR loop. Can anyone help with some example please?
The basic structure of what you are asking can be seen below.
Please provide more information for a more specific code sample.
DECLARE
l_output NUMBER;
BEGIN
FOR i IN 1..10 LOOP
SELECT 1
INTO l_output
FROM dual;
DBMS_OUTPUT.PUT_LINE('Result: ' || l_output);
END LOOP;
END;
PS: If you need to enable output in SQL*Plus, you may need to run the command
SET SERVEROUTPUT ON
UPDATE
To insert your results in another table:
DECLARE
-- Store the SELECT query in a cursor
CURSOR l_cur IS SELECT SYSDATE DT FROM DUAL;
--Create a variable that will hold each result from the cursor
l_cur_rec l_cur%ROWTYPE;
BEGIN
-- Open the Cursor so that we may retrieve results
OPEN l_cur;
LOOP
-- Get a result from the SELECT query and store it in the variable
FETCH l_cur INTO l_cur_rec;
-- EXIT the loop if there are no more results
EXIT WHEN l_cur%NOTFOUND;
-- INSERT INTO another table that has the same structure as your results
INSERT INTO a_table VALUES l_cur_rec;
END LOOP;
-- Close the cursor to release the memory
CLOSE l_cur;
END;
To create a View of your results, see the example below:
CREATE VIEW scott.my_view AS
SELECT * FROM scott.emp;
To view your results using the view:
SELECT * FROM scott.my_view;
I'm attempting to write a stored proc that takes in a number, n, and returns the first n results for a given query, exclusively locking those n rows. I'm a little new to SQL and I'm having a bit of difficulty matching data types correctly.
My package spec looks like this:
PACKAGE package IS
Type out_result_type is REF CURSOR;
PROCEDURE stored_proc
(in_n IN NUMBER DEFAULT 10,
out_list IN OUT out_result_type);
I then define the cursor in the procedure body, like so:
CURSOR OUT_RESULT_TYPE IS
SELECT a.id
FROM schema.table a
WHERE (some conditions) AND rownum <= in_n;
A bit later on I then try to extract the results of the cursor into the output variable:
OPEN OUT_RESULT_TYPE;
FETCH OUT_RESULT_TYPE INTO out_list; -- error on this line
CLOSE OUT_RESULT_TYPE;
But alas this code doesn't compile; oracle complains that out_list has already been defined with a conflicting data type. Any idea how I can resolve this issue? It's driving me crazy!
Thanks in advance.
CREATE OR REPLACE PACKAGE pkg_test
AS
TYPE tt_cur IS REF CURSOR;
PROCEDURE prc_cur (retval OUT tt_cur);
END;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur (retval OUT tt_cur)
AS
BEGIN
OPEN retval
FOR
SELECT *
FROM dual;
END;
END;
If you want to lock, use:
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur (retval OUT tt_cur)
AS
BEGIN
OPEN retval
FOR
SELECT a.id
FROM schema.table a
WHERE (some conditions)
AND rownum <= in_n
ORDER BY
column
-- Never forget ORDER BY!
FOR UPDATE;
END;
END;
Two remarks:
A cursor doesn't lock.
You don't have to do Type out_result_type is REF CURSOR;, use default type sys_refcursor. See here: Oracle - How to have an out ref cursor parameter in a stored procedure?
Your out_list must be of wrong type. Consider (script run on 10.2.0.3):
CREATE TABLE t AS SELECT ROWNUM ID FROM all_objects WHERE ROWNUM <= 100;
CREATE OR REPLACE PACKAGE cursor_pck AS
TYPE out_result_type is REF CURSOR;
PROCEDURE stored_proc (p_in IN NUMBER DEFAULT 10,
p_out_list IN OUT out_result_type);
END cursor_pck;
/
If you want to select and lock the rows at the same time you would use the FOR UPDATE clause:
CREATE OR REPLACE PACKAGE BODY cursor_pck AS
PROCEDURE stored_proc (p_in IN NUMBER DEFAULT 10,
p_out_list IN OUT out_result_type) IS
BEGIN
OPEN p_out_list FOR SELECT a.id FROM t a WHERE ROWNUM <= p_in FOR UPDATE;
END stored_proc;
END cursor_pck;
/
With the following setup, you will call the procedure like this:
SQL> SET SERVEROUTPUT ON;
SQL> DECLARE
2 l_cursor cursor_pck.out_result_type;
3 l_id t.id%TYPE;
4 BEGIN
5 cursor_pck.stored_proc(3, l_cursor);
6 LOOP
7 FETCH l_cursor INTO l_id;
8 EXIT WHEN l_cursor%NOTFOUND;
9 dbms_output.put_line(l_id);
10 END LOOP;
11 END;
12 /
1
2
3
PL/SQL procedure successfully completed
This is not going to work the way it's written, because
out_list expects a cursor, not a cursor result.
The name out_result_type is already used for a type, so you can't redefine it to be a cursor in the same scope.
Oracle provides a pre-defined weak reference cursor: sys_refcursor. In usage it would look like:
CREATE OR REPLACE PACKAGE pkg_test
AS
PROCEDURE prc_cur (p_retval OUT sys_refcursor,
p_lookup IN VARCHAR2);
END pkg_test;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur(p_retval OUT sys_refcursor
p_lookup IN VARCHAR2)
IS
BEGIN
OPEN retval FOR SELECT a.value
FROM tblname a
WHERE a.id <= p_lookup;
END prc_cur;
END pkg_test;
This saves you the trouble of needing to declare a type. The sys_refcursor is a pointer to a result set from an open cursor. If you are familiar with Java, it's the same concept as the java.sql.ResultSet object which provides a way to get at the results of a query.