Inserting values in to netezza using a stored procedure - stored-procedures

I'm working with netezza database and have a requirement to insert a Y flag for stores in California. I wrote the below procedure
CREATE OR REPLACE PROCEDURE MY_NEW_PROCEDURE() RETURNS BOOL
EXECUTE AS OWNER LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
rec RECORD;
BEGIN
FOR rec in SELECT * from test_table
LOOP
if rec.state_code ='CA'
EXECUTE IMMEDIATE 'INSERT INTO test_table (california_stores)' || 'values('y')';
END LOOP;
END;
END_PROC;
when I call the procedure using call MY_NEW_PROCEDURE() I get an error at line EXECUTE IMMEDIATE. I'm not sure what change I need to make here.

Don't know about netezza, but below is the procedure I used to test this (using SQL developer).
Works fine for me, although it would make more sense to update the row to set california_stores to 'Y'rather than insert a new row with california_stores = 'Y' for each calafornia store that you have.....
CREATE OR REPLACE PROCEDURE "MY_NEW_PROCEDURE" as
rec test_table2%rowtype;
BEGIN
FOR rec in (SELECT * from test_table2) LOOP
if rec.state_code = 'CA' then
EXECUTE IMMEDIATE 'INSERT INTO test_table2 (california_stores)' || 'values(''y'')';
end if;
END LOOP;
END;

You didn't post the second error, but it looks to me like your insert statement isn't going to do what you want anyway. If the rec variable contains the attribute state_code and you're inserting a single value to test_table then the record will simply be empty except for a 'Y' in california_stores.
I'm going to guess that you're getting an error now either because of the spacing in the insert statement insert into test_table (california_stores)values('y') or because you didn't terminate the execute statement with a semicolon. The plsql for that line should be
execute immediate 'insert into test_table (california_stores) values (''y'');';

Related

Set a variable value in stored procedure and use in following query

How can I set a variable in stored procedure and use it in following query to be executed.
create or replace procedure sp1()
returns table (dealer_id varchar, dealershipgroup_name varchar)
language sql
as
$$
declare
create_query varchar;
res resultset;
MISSING_DEALER NUMBER(38,0) default 0;
begin
MISSING_DEALER := 100;
select_query := 'WITH CTE AS(
SELECT dealer_id,
CASE WHEN dealer_id=:MISSING_DEALER then \'Abc\'
WHEN dealershipgroup IS NULL then \'\'
ELSE dealershipgroup end as dealershipgroup FROM TBL )
select * from CTE';
res:= (execute immediate : select_query);
return table(res);
end;
$$;
call sp1();
Could someone please suggest how can I use MISSING_DEALER in the query. I am currently getting the following error
Uncaught exception of type 'STATEMENT_ERROR' on line 28 at position 9 : SQL compilation error: error line 8 at position 26 Bind variable :MISSING_DEALER not set
You need to concatenate the string parts of your SQL statement with the variable. This is covered in the documentation if you look at the end of the section here

Is it possible to pass in a variable amount of parameters to a stored procedure in redshift?

I am trying to write a stored procedure in AWS Redshift SQL and one of my parameters needs the possibility to have an integer list (will be using 'IN(0,100,200,...)' inside there WHERE clause). How would I write the input parameter in the header of the procedure so that this is possible (if at all?)
I've tried passing them in as a VARCHAR "integer list" type thing but wasn't sure then how to parse that back into ints.
Update: I found a way to parse the string and loop through it using the SPLIT_PART function and store all of those into a table. Then just use a SELECT * FROM table with the IN() call
What I ended up doing was as follows. I took in the integers that I was expecting as a comma-separated string. I then ran the following on it.
CREATE OR REPLACE PROCEDURE test_string_to_int(VARCHAR)
AS $$
DECLARE
split_me ALIAS FOR $1;
loop_var INT;
BEGIN
DROP TABLE IF EXISTS int_list;
CREATE TEMPORARY TABLE int_list (
integer_to_store INT
);
FOR loop_var IN 1..(REGEXP_COUNT(split_me,',') + 1) LOOP
INSERT INTO int_list VALUES (CAST(SPLIT_PART(split_me,',',loop_var) AS INT));
END LOOP;
END;
$$ LANGUAGE plpgsql;
So I would call the procedure with something like:
CALL test_string_to_int('1,2,3');
and could do a select statement on it to see all the values stored into the table. Then in my queries the need this parameter I ran:
.........................
WHERE num_items IN(SELECT integer_to_store FROM int_list);

PL SQL Procedure Exercise

I'm not really sure how to approach this question.. I understand the basic syntax of writing a procedure. This is an exercise for a beginner database class (which seems to be at a level way above beginner)
Create a procedure to place a purchase order for a specified date based on data in the inventory report table.
Name the procedure placeorder [procedure name is important].
The procedure should take one parameter: inputDate (use the datatype of the PODate column in PURCHASEORDERS). The input date format accepted should be: 'DD-MON-YYYY', e.g., 01-JAN-2017.
For each raw material in the Inventory Report table (where: ReportDate matches inputDate), make a separate entry in the PURCHASEORDERS table for a next-day delivery order and a same-day delivery order (each raw material may generate up to 2 inserts).
Corresponding order type should be either next_day or same_day
Only make an entry (insertion) in PURCHASEORDERS if needed, i.e., if
an entry exists for a raw material and report date combination in the
Inventory Report table. If the Inventory Report for a day (e.g.,
30-NOV-2017) has a 0 value for the ordersameday attribute, it means
no same_day order is needed.
If no order is needed for the provided input date (i.e., no order at all across ALL raw materials), raise an application error with a message: “no order needed” (see Triggers and Procedures tutorial on D2L for an example of how to raise this error). You can use any suitable error-number.  Your procedure should leave the “Price” (for the purchase order) empty (i.e., it can remain null). Assume it’ll be populated later.
Thanks!
Sorry this is what i've written so far.. #kara
CREATE OR REPLACE PROCEDURE placeorder (inputDate in DATE)
AS
new_inputDate PURCHASEORDERS.PODate%TYPE;
new_orderType PURCHASEORDERS.ORDERTYPE%TYPE;
c_orderSameDay INVENTORYREPORT.ORDERSAMEDAY%TYPE;
c_orderNextDay INVENTORYREPORT.ORDERNEXTDAY%TYPE;
CURSOR C1 IS
SELECT REPORTDATE INTO inputDate FROM dual;
SELECT ir.itemId, ir.ORDERSAMEDAY, ir.ORDERNEXTDAY FROM INVENTORYREPORT
WHERE
ir.REPORTDATE = inputDate;
BEGIN
OPEN C1;
WHILE C1%FOUND LOOP
FETCH C1 INTO new_inputDate, new_orderType, c_orderSameDay, c_orderNextDay;
IF c_orderSameDay > 0
THEN INSERT INTO PURCHASEORDERS (new_orderType) VALUES (orderSameDay);
ELSE <application error>;
END IF;
IF c_orderNextDay > 0
THEN INSERT INTO PURCHASEORDERS (new_orderType) VALUES (orderNextDay);
ELSE <application error>;
END IF;
END LOOP;
CLOSE C1;
END;
/
#kara I added to the if statements but still getting a couple errors when trying to compile the procedure. It this doing what it's supposed to be doing?
CREATE OR REPLACE PROCEDURE placeorder (inputDate in DATE)
AS
new_inputDate PURCHASEORDERS.PODate%TYPE;
new_orderType PURCHASEORDERS.ORDERTYPE%TYPE;
c_orderSameDay INVENTORYREPORT.ORDERSAMEDAY%TYPE;
c_orderNextDay INVENTORYREPORT.ORDERNEXTDAY%TYPE;
CURSOR C1 IS
SELECT REPORTDATE INTO inputDate FROM dual;
SELECT ir.itemId, ir.ORDERSAMEDAY, ir.ORDERNEXTDAY FROM INVENTORYREPORT
WHERE
ir.REPORTDATE = inputDate;
BEGIN
OPEN C1;
WHILE C1%FOUND LOOP
FETCH C1 INTO new_inputDate, new_orderType, c_orderSameDay, c_orderNextDay;
IF c_orderSameDay > 0
THEN INSERT INTO PURCHASEORDERS (new_orderType) VALUES (orderSameDay);
ELSE INSERT INTO PURCHASEORDERS (new_orderType) VALUES ('no order needed');
END IF;
IF c_orderNextDay > 0
THEN INSERT INTO PURCHASEORDERS (new_orderType) VALUES (orderNextDay);
ELSE INSERT INTO PURCHASEORDERS (new_orderType) VALUES ('no order needed');
END IF;
FETCH C1 INTO new_inputDate, new_orderType, c_orderSameDay, c_orderNextDay;
END LOOP;
CLOSE C1;
COMMIT;
END placeorder;
/
There are a bunch of examples how to create a procedure. Here a small one:
CREATE OR REPLACE PROCEDURE ProcName (paraName IN VARCHAR2)
AS
myStringVariable VARCHAR2 (4000);
myDateVariable DATE;
BEGIN
SELECT orderDateAsString
INTO myStringVariable
FROM orders
WHERE orderId = paraName;
myDateVariable := TO_DATE (myStringVariable, 'dd.mm.yyyy HH24:MI:SS'); -- '13.03.2018 23:59:59'
dbms_output.put_line('My date: ' || myStringVariable);
END;
And some example-code, to call the procedure:
begin
ProcName('1234');
end;
But you should look at your exercise first and think about you tasks. I think, this is what you got to do:
Create a Table.
Create Insert-Statements for the table
Create some PL/SQL-code which performs the insert with conditions.
move the PL/SQL-code to a procedure.
Call the procedure with a PL/SQL-block.
Explaination for you edits
You should build your code step-by-step if. You got multiple errors.
Check you Cursor. The Select-statement is not valid.
You wrote two selects.
You do not use new_inputdate. Why did you define it and what should it do?
Run you SELECT-statement alone without your code. if you like your data you can put it in an cursor.
Example with your code:
CREATE OR REPLACE PROCEDURE placeorder (inputDate IN DATE)
AS
-- new_inputDate PURCHASEORDERS.PODate%TYPE; --you don't use this one
new_orderType PURCHASEORDERS.ORDERTYPE%TYPE;
c_orderSameDay INVENTORYREPORT.ORDERSAMEDAY%TYPE;
c_orderNextDay INVENTORYREPORT.ORDERNEXTDAY%TYPE;
-- you mixed up your cursors. seems like you didn't try the select-statement alone..
CURSOR C2
IS
SELECT ir.itemId, ir.ORDERSAMEDAY, ir.ORDERNEXTDAY
FROM INVENTORYREPORT
WHERE ir.REPORTDATE = inputDate;
BEGIN
OPEN C2;
WHILE C2%FOUND
LOOP
FETCH C2 INTO new_orderType, c_orderSameDay, c_orderNextDay;
NULL; -- Do something
END LOOP;
CLOSE C2;
END;
/
Think about what you want to do in the loop. Build a small skript with the variables and think about what it should do:
Example-Skript of you Loop-content:
DECLARE
-- new_inputDate PURCHASEORDERS.PODate%TYPE; --you don't use this one
new_orderType NUMBER := 0;
c_orderSameDay NUMBER := 1;
c_orderNextDay NUMBER := 2;
BEGIN
-- this is what you're doing in you loop.
IF c_orderSameDay > 0 -- check if c_orderSameDay is greater than 0? In Oracle you use 'NULL' as empty value. Perhaps it should be 'c_orderSameDay IS NOT NULL'
THEN
INSERT INTO PURCHASEORDERS (new_orderType) -- you perform your insert.
VALUES (orderSameDay);
ELSE
RAISE; -- you raise an exception? this means c_orderSameDay has alsway to be set.
END IF;
IF c_orderNextDay > 0
THEN
INSERT INTO PURCHASEORDERS (new_orderType)
VALUES (orderNextDay);
ELSE
RAISE; -- you raise an exception? this means c_orderNextDay has alsway to be set.
END IF;
END;

How to insert return value from last EXECUTE PROCEDURE in INFORMIX

This should be relatively easy but I'm new with informix.
I have a stored proc that I am calling with EXECUTE PROCEDURE. The proc is roughly as follows (but with a ton more columns):
CREATE PROCEDURE MYPROC (
foo int,
bar int
) returning int;
How can I use that int from the Informix prompt to use it in a subsequent insert?
This is roughly what I would like to do. I do not have the option to change the insides of the proc.
> EXECUTE PROCEDURE MYPROC(foo,bar);
(expression)
4104
1 row(s) retrieved.
> INSERT INTO MYTABLE(val) VALUES(I_DONT_KNOW_WHAT_GOES_HERE);
I have already tried this
> INSERT INTO MYTABLE(val) VALUES(
EXECUTE PROCEDURE MYPROC(foo,bar)
);
and failed!
You can use the output of a FUNCTION or PROCEDURE in most places where an expression is expected. So this should be all you need:
> INSERT INTO MYTABLE(val) VALUES( MYPROC(foo,bar) );
Update
Further discussion in comments has identified that the procedure has some DML in it, so the solution above does not work. (Informix does not permit this, presumably to avoid endless looping and recursion).
You might have more luck with this (untested):
INSERT INTO mytable
SELECT a.result FROM TABLE(myproc('foo','bar')) AS a(result)
But it might also be refused for the same reason as the original.

How to use procedure parameters in merge statement

i'm creating a procedure to update/insert a table using merge statement(upsert).now i have a problem: using procedure parameters i have to do this upsert.
procedure xyz( a in table.a%type,b in table.b%type,....)
is
some local variables;
begin
merge into target_table
using source_table --instead of the source table, i have to use procedure parameters here
on (condition on primary key in the table)
when matched then
update the table
when not matched then
insert the table ;
end xyz;
so how to use procedure parameters instead of source table in merge statement?? or
suggest me a query to fetch the procedure parameters and use it as source table values.
help me please.
Thanks in advance.
I know that I'm eight years late to the party, but I think that I was trying to do something similar to what you were doing, but trying to Upsert based on parameters passed into a stored procedure that returns an empty string on success and an error on failure back to my VB Code. Below is all of my code along with comments explaining what I did, and why I did it. Let me know if this helps you or anyone else. This is my first time answering a post.
PROCEDURE UpsertTSJobData(ActivitySeq_in IN NUMBER,
Owner_in In VARCHAR2,
NumTrailers_in IN NUMBER,
ReleaseFormReceived_in IN NUMBER,
Response_out OUT VARCHAR2) AS
err_num NUMBER;
err_msg VARCHAR2(4000);
BEGIN
--This top line essentially does a "SELECT *" from the named table
--and looks for a match based on the "ON" statement below
MERGE INTO glob1app.GFS_TS_JOBDATA_TAB tsj
--This select statement is used for the INSERT when no match
--is found and the UPDATE when a match is found.
--It creates a "pseudo-table"
USING (
SELECT ActivitySeq_in AS ActSeq,
Owner_in As Owner,
NumTrailers_in As NumTrailers,
ReleaseFormReceived_in As ReleaseFormReceived
FROM DUAL) input
--This ON statement is what we're doing the match on to find
--matching records. This decides whether it will be an
--INSERT or an UPDATE
ON (tsj.Activity_seq = ActivitySeq_in)
WHEN MATCHED THEN
--Here we UPDATE based on the passed in input table
UPDATE
SET OWNER = input.owner,
NUMTRAILERS = input.NumTrailers,
RELEASEFORMRECEIVED = input.releaseformreceived
WHEN NOT MATCHED THEN
--Here we INSERT based on the passed in input table
INSERT (
ACTIVITY_SEQ,
OWNER,
NUMTRAILERS,
RELEASEFORMRECEIVED
)
VALUES (
input.actseq,
input.owner,
input.numtrailers,
input.releaseformreceived
);
Response_out := '';
EXCEPTION
WHEN OTHERS THEN
err_num := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 3900);
Response_out := TO_CHAR (err_num) || ': ' || err_msg;
END;
Maby something like
DECLARE V_EXISTS NUMBER;
BEGIN SELECT COUNT(*) INTO V_EXISTS FROM TARGET_TABLE WHERE PK_ID = :ID;
IF V_EXISTS > 0 THEN
-- UPDATE
ELSE
-- INSERT
END IF;
END;
Also, you may try to use so-called tempotary table (select from DUAL)
CREATE TABLE TEST (N NUMBER(2), NAME VARCHAR2(20), ADRESS VARCHAR2(100));
INSERT INTO TEST VALUES(1, 'Name1', 'Adress1');
INSERT INTO TEST VALUES(2, 'Name2', 'Adress2');
INSERT INTO TEST VALUES(3, 'Name3', 'Adress3');
SELECT * FROM TEST;
-- test update
MERGE INTO TEST trg
USING (SELECT 1 AS N, 'NameUpdated' AS NAME,
'AdressUpdated' AS ADRESS FROM Dual ) src
ON ( src.N = trg.N )
WHEN MATCHED THEN
UPDATE
SET trg.NAME = src.NAME,
trg.ADRESS = src.ADRESS
WHEN NOT MATCHED THEN
INSERT VALUES (src.N, src.NAME, src.ADRESS);
SELECT * FROM TEST;
-- test insert
MERGE INTO TEST trg
USING (SELECT 34 AS N, 'NameInserted' AS NAME,
'AdressInserted' AS ADRESS FROM Dual ) src
ON ( src.N = trg.N )
WHEN MATCHED THEN
UPDATE
SET trg.NAME = src.NAME,
trg.ADRESS = src.ADRESS
WHEN NOT MATCHED THEN
INSERT VALUES (src.N, src.NAME, src.ADRESS);
SELECT * FROM TEST;
DROP TABLE TEST;
see here
Its very difficult to tell from you question exactly what you what, but I gather you want the table that you are merging into ( or on ) to be dynamic. In that case, what you should be using is the DBMS_SQL package to create dynamic SQL

Resources