Db2 stored procedure to insert - sql

I'm new to db2 and stored procedure i created a stored procedure to insert records into a database but the stored procedure doesn't work, the code is as follows:
drop procedure product_create ;
CREATE PROCEDURE product_Create(
out errmsg char(256),
in inCucode char(6),
in inProdCode char(25),
in inDescription char(80),
in inUPC char(25),
in inuom char(3),
in instdpack decimal(5,0),
in inweight decimal(9,4),
in inlength decimal(9,4),
in inwidth decimal(9,4),
in inheight decimal(9,4)
)
language sql
BEGIN
if errmsg = ' '
insert INTO prmast
( prcucd,
prprcd,
prdes1,
prupc#,
prworu,
prwuts,
prntwt,
prlong,
prwide,
prhigh
)
values ( inCucode,
inProdCode,
inDescription,
inUPC,
inuom,
instdpack,
inweight,
inlength,
inwidth,
inheight,
) ;
end if ;
return ;
end
Is this the correct structure for an insert query in stored procedure am i forgetting anything, your help will be appreciated.

I reproduced your issue as following:
Create a table "prmast":
CREATE TABLE prmast(prcucd char(6), prprcd char(25), prdes1 char(80), prupc# char(25), prworu char(3), prwuts dec(5,0), prntwt dec(9,4), prlong dec(9,4), prwide dec(9,4), prhigh dec(9,4));
Write the stored procedure and save it to a file called sol.txt
CREATE OR REPLACE PROCEDURE product_Create(
out errmsg char(5),
in inCucode char(6),
in inProdCode char(25),
in inDescription char(80),
in inUPC char(25),
in inuom char(3),
in instdpack decimal(5,0),
in inweight decimal(9,4),
in inlength decimal(9,4),
in inwidth decimal(9,4),
in inheight decimal(9,4)
)
language sql
BEGIN
DECLARE SQLSTATE CHAR(5);
Insert INTO prmast
( prcucd,
prprcd,
prdes1,
prupc#,
prworu,
prwuts,
prntwt,
prlong,
prwide,
prhigh
)values
( inCucode,
inProdCode,
inDescription,
inUPC,
inuom,
instdpack,
inweight,
inlength,
inwidth,
inheight
) ;
SET errmsg = SQLSTATE;
end#
run the procedure: db2 -td# -vf sol.txt
Then, I call the procedure:
db2 "call product_Create(?, 'a','b','c','d','e',6,7,8,9,10)"
Value of output parameters
Parameter Name : ERRMSG
Parameter Value : 00000
Return Status = 0`
Verify it works:
`db2 select * from prmast
PRCUCD PRPRCD PRDES1 PRUPC# PRWORU PRWUTS PRNTWT PRLONG PRWIDE PRHIGH
------ ------------------------- -------------------------------------------------------------------------------- ------------------------- ------ ------- ----------- ----------- ----------- ---------
a b c d e 6. 7.0000 8.0000 9.0000 10.00
00
1 record(s) selected.`
There are several points to be noticed for your procedure:
You can use CREATE OR REPLACE PROCEDURE to define your procedure. It will drop existing procedure definition and replace it with the definition you just run. In other words, you don't have to explicitly DROP PROCEDURE
char(255) is out of range. declare output "errmsg" as char(5) should be good enough.
You can use SET statement to explicitly check if your SQL statement executed successfully or not.
The # symbol at the end of procedure indicates db2 that to not use ; as end of statement because you use ; as end of statement of a SQL, which belongs to part of stored procedure definition. That is also why you want to use -td# option when you execute your clp. That tells DB2 to use # instead of ; as end-of-statement symbol.
Also, there is , right after column "inheight", which is the last column and should not have , following
When calling stored procedure, ? is required as placeholder for "OUT" parameter.
One more note, if you want to insert values from the selection result of another table, you may want to use "cursor" instead of explicitly supplying the values to your stored procedure.

Related

stored procedure, handle possible null value

I have a very simple stored procedure which currently works perfectly when both parameters are sent values from form inputs.
However, I need to figure out what to do for IN_NUMBER if the value is empty because that column in the destination table is set to be nullable. It seems like the procedure itself is simply failing because it's waiting for a value.
What should I change?
IN parameters:
IN_NAME
IN_NUMBER
Routine:
P1 : BEGIN ATOMIC
INSERT INTO schema . postings
( name
, postNumber)
VALUES
( IN_NAME
, IN_NUMBER) ;
END P1
Example:
create table postings (name varchar(100), postNumber int) in userspace1#
create or replace procedure postings (
in_name varchar(100)
, in_number int
)
P1 : BEGIN ATOMIC
INSERT INTO postings
( name
, postNumber)
VALUES
( IN_NAME
, IN_NUMBER) ;
END P1#
call postings('myname', null)#
select * from postings#
NAME POSTNUMBER
---- ----------
myname <null>
There is no any problem here as you see.
What db2 error do you have exactly on a case similar to this?
If you want to handle NULL and replace it with some other value, use NVL(IN_NUMBER, 0) - you can exchange 0 for any other number of course (I'm assuming this is an integer).

Dynamic SQL (where) in Firebird stored procedure

I Have an SP that receive 2 parameters, P1 and P2, like this:
CREATE OR ALTER PROCEDURE MY_PROC (P1 varchar(10), P2 smallint = 1)
RETURNS (
code VARCHAR(10),
name VARCHAR(70),
state VARCHAR(2),
situation VARCHAR(20)
AS
...
...
And I need to generate the where clause based on the P2 parameter, like this:
if (P2=1) then
where (state='SP' and situation='stopped')
elseif (P2=2)
where (state='MG' and situation='moving')
How to use this type of if statement in where clause?
To me your question translates as a simple OR condition in the WHERE clause of a SQL query:
WHERE
(:P2 = 1 AND state='SP' and situation='stopped')
OR (:P2 = 2 AND state='MG' and situation='moving')
The answer of GMB will work fine for most situations, but in more complex cases it may have less desirable performance. An alternative solution would be to build a query string dynamically and execute it with execute statement:
CREATE OR ALTER PROCEDURE MY_PROC (P1 varchar(10), P2 smallint = 1)
RETURNS (
code VARCHAR(10),
name VARCHAR(70),
state VARCHAR(2),
situation VARCHAR(20)
AS
declare query varchar(2048);
begin
query = 'select ......';
if (p2 = 1) then
query = query || ' where (state=''SP'' and situation=''stopped'')';
else if (p2 = 2) then
query = query || ' where (state=''MG'' and situation=''moving'')';
-- if you expect a single result
execute statement query into code, name, state, situation;
-- OR
-- for multiple results
for execute statement query into code, name, state, situation do
suspend;
end

HSQLDB Stored Procedure Error: attempt to assign to non-updatable column

I am using HSQLDB 2.3.2 and am getting a bizarre error when trying to create a stored procedure.
My addresses table:
CREATE TABLE IF NOT EXISTS addresses (
address_id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL PRIMARY KEY,
address_line_1 NVARCHAR(500) NOT NULL,
address_line_2 NVARCHAR(500),
address_city NVARCHAR(100) NOT NULL,
address_postal_code NVARCHAR(25) NOT NULL,
CONSTRAINT uc_addresses UNIQUE (address_line_1, address_city)
)
An insert to populate it:
INSERT INTO addresses (
address_line_1,
address_city,
address_postal_code
) VALUES (
'123 Test Blvd.', 'Testville', '11111'
)
And my proc:
CREATE PROCEDURE sp_get_address_by_id(
IN address_id INTEGER,
OUT address_id INTEGER,
OUT address_line_1 NVARCHAR(500),
OUT address_line_2 NVARCHAR(500),
OUT address_city NVARCHAR(100),
OUT address_postal_code NVARCHAR(25))
READS SQL DATA
BEGIN ATOMIC
SELECT
a.address_id,
a.address_line_1,
a.address_line_2,
a.address_city,
a.address_postal_code
INTO
address_id,
address_line_1,
address_line_2,
address_city,
address_postal_code
FROM
addresses a
WHERE
a.address_id = address_id;
END
When I run this I get:
Error: attempt to assign to non-updatable column
SQLState: 0U000
ErrorCode: -2500
Questions:
What is wrong with my proc (what is producing this error)?
I'm actually looking for a CREATE IF NOT EXISTS-type declaration, so I can run this script over and over again and the procedure will only get created one time if it doesn't already exist. Will this happen or do I need to change the syntax to accomplish IF NOT EXISTS?
Try the syntax below, according to the hsqldb documentation
http://hsqldb.org/doc/2.0/guide/sqlroutines-chapt.html#src_psm_assignment
The SET statement is used for assignment. It can be used flexibly with
rows or single values.
Also change the address_id parameter to type INOUT and remove the duplicate address_id parameter lines.
CREATE PROCEDURE sp_get_address_by_id(
INOUT address_id INTEGER,
OUT address_line_1 NVARCHAR(500),
OUT address_line_2 NVARCHAR(500),
OUT address_city NVARCHAR(100),
OUT address_postal_code NVARCHAR(25))
READS SQL DATA
BEGIN ATOMIC
SET (address_id,
address_line_1,
address_line_2,
address_city,
address_postal_code)
=
(
SELECT
a.address_id,
a.address_line_1,
a.address_line_2,
a.address_city,
a.address_postal_code
FROM
addresses a
WHERE
a.address_id = address_id
);
END
You can try adding this as the first statement in your script if you want to drop the procedure if it already exists, so that you can re-run the script many times. You can search the documentation for <specific routine designator> for more info.
DROP SPECIFIC PROCEDURE sp_get_address_by_id IF EXISTS;
In your procedure you have two parameters with the same name:
IN address_id INTEGER,
OUT address_id INTEGER,
It may cause a problem when you refer to address_id in the body of procedure.
You should rather use:
INOUT address_id INTEGER,
instead of these two lines.
Answering your second question:
Why do you want to run this script over and over again without rebuilding the procedure? Running this script again has sense when something has changed in it.
If you don't plan to change this procedure but you want to change other things in your script then maybe you should simply move this procedure to other script and run it only once
If you plan to change the body of procedure then it should be rebuilded every time. So you should use CREATE OR REPLACE PROCEDURE
For followers, the same error message is thrown if you do this:
PreparedStatement selectStmt = conn.prepareStatement(query);
ResultSet rs = selectStmt.executeQuery()) {
rs.next();
rs.updateLong("column", value); // boom
one fix is to use this style:
PreparedStatement selectStmt =
conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

SQL procedure to add and edit data

Im busy with an old exam paper one of the questions read as follows
Study the following tables and answer the questions below:
CREATE TABLE CARDHOLDERS(
CH_ID INTEGER IDENTITY,
CH_NAME VARCHAR(50),
CH_SURNAME VARCHAR(50),
CH_IDNUMBER CHAR(13),
CH_CARDNUMBER CHAR(13),
CH_STATUS CHAR(2),
CH_CREATE_DATE DATETIME,
CH_LAST_CHANGE_DATE DATETIME)
Write a store procedure to add or edit the cardholders information. Do the neccecary validation checks to ensure data is correct.
My Answer
Create Procedure add_ch (#CH_NAME, #CH_SURNAME...)
AS
BEGIN
INSERT INTO CARDHOLDERS VALUES (#CH_NAME, #CH_SURNAME...)
END
TO RUN PROCEDURE
EXECUTE add_ch ('Peter', 'Kemp')
My Question
Will the above procedure to add cardholer give the correct results?
The Question asks 'Write a store procedure to add or edit the
cardholders information' how do I combine the add procedure with
the edit cardholder procedure or am I correct in assuming that I can
have to different procedure?
Are you looking for something like this?
CREATE PROCEDURE add_ch (#CH_NAME , #CH_SURNAME...)
AS
BEGIN
DECLARE #count INT
SET #count =
(SELECT count (*)
FROM CARDHOLDERS
WHERE CH_NAME = #CH_NAME AND CH_SURNAME = #CH_SURNAME)
IF #count = 0
INSERT INTO CARDHOLDERS
VALUES (#CH_NAME, #CH_SURNAME...)
else Print'This user already exsit.'
END
Try something like this. Using decode and setting defaults for the parameters helps.
create or replace procedure add_ch
(
CHID INTEGER := -1,
CHNAME VARCHAR := '#',
CHSURNAME VARCHAR := '#',
CHIDNUMBER CHAR := '#',
CH_CARDNUMBER CHAR := '#',
CHSTATUS CHAR := '#',
CHCREATE_DATE DATETIME := '01-Jan-1900',
CHLAST_CHANGE_DATE DATETIME:= '01-Jan-1900'
)
as
begin
update cardholders
set CH_NAME = decode( CHNAME,'#',CH_NAME,chname ),
CH_SURNAME = decode( CHSURNAME,'#',CH_SURNAME, CHSURNAME),....
where CH_ID = CHID;
if sql%notfound
then
insert into cardholders
(
CH_ID,
CH_NAME,
CH_SURNAME,
CH_IDNUMBER,
CH_CARDNUMBER,
CH_STATUS,
CH_CREATE_DATE,
CH_LAST_CHANGE_DATE
)
values
(
CHID,
CHNAME,
CHSURNAME,
CHIDNUMBER,
CH_CARDNUMBER,
CHSTATUS CHAR,
CHCREATE_DATE,
CHLAST_CHANGE_DATE
);
end;
first of all You Have to find The primary key data in your database table
if exist data in DBtable(with current primary key value)
then execute your update sql query
else
execute your insert query.
Done your database checking using the previous answer to your question.

Array as input variable in Stored Procedure [duplicate]

I have a list ClaimData in C# and it has three items Date, Type and Description
There can be multiple rows in this as below,
ClaimData
Date Type Description
01/02/2012 "Medical" "Its a medical"
05/02/2013 "Theft" "Its a Theft"
01/02/2014 "Test" "Its a Test"
I want to pass this whole data to a stored procedure in one go to the sql server, so that I can reduce the database hits. I have written stored procedure which can iterate through this list and insert them in a table.
How to achieve by manipulating the list object could be passed to the stored procedure as a parameter?
You will need to do a couple of things to get this going, since your parameter is getting multiple values you need to create a Table Type and make your store procedure accept a parameter of that type.
Since you are passing a TABLE as a parameter you will need to create a TABLE TYPE something as follows
TABLE TYPE
CREATE TYPE dbo.ClaimData AS TABLE
(
[Date] DATE
[Type] VARCHAR(50)
[Description] VARCHAR(100)
)
GO
Stored Procedure to Accept That Type Param
CREATE PROCEDURE mainValues
#TableParam ClaimData READONLY --<-- Accepts a parameter of that type
AS -- Note it is ReadOnly
BEGIN
SET NOCOUNT ON;
--Temp table to store the passed values
-- since the passed parameter is only Read only and you
-- cannot make any changes to the parameter so if you need to
-- manipulate the data inside parameter you will need to get it
-- into a Table vaiable.
-- Declare a Table variable
DECLARE #tmp_values table(
[Date] DATE
[Type] VARCHAR(50)
[Description] VARCHAR(100)
);
--Get values into that Table variable
INSERT INTO #tmp_values ([Date],[Type],[Description])
SELECT [Date],[Type],[Description] FROM #TableParam
-- Do other cool stuff with your passed data
SELECT * FROM #tmp_values --<-- For testing purpose
END
EXECUTE PROC
Declare a variable of that type and populate it with your values.
DECLARE #Table ClaimData( --<-- Declare a variable of your type
[Date] DATE
[Type] VARCHAR(50)
[Description] VARCHAR(100)
);
-- Populate the variable
INSERT INTO #Table ([Date],[Type],[Description])
SELECT [Date],[Type],[Description] FROM Source_Table
EXECUTE mainValues #Table --<-- Stored Procedure Executed
I sent all three column as a string using string builder and delimeter '|'
DateString = '01/02/2012|05/02/2013|01/02/2014'
TypeString = 'Medical|Theft|Test'
DescString = "Its a medical|..."
On database side I used a function to delimit these strings and inserted all these values in a temp table. This solved my problem.