stored procedure, handle possible null value - sql

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).

Related

Db2 stored procedure to insert

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.

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.

Architecture : In SQL what is the best method to query a filtered data set?

In SQL what is the best method to query a filtered data set?
I imagined two solutions and I would like to know what are the advantages and incovenients one and the other.
Solution 1
I create one unique procedure with my filter in parameters
CREATE PROCEDURE [dbo].[usp_GetByFilter]
(
-- Pagination
#p_Offset int,
#p_FetchNext int,
-- Filters
#p_Param1 nvarchar(255),
#p_param2 uniqueidentifier,
#p_param3 uniqueidentifier
)
Solution 2
I create a procedure by parameter
CREATE PROCEDURE [dbo].[usp_GetByParam1]
(
-- Pagination
#p_Offset int,
#p_FetchNext int,
-- Filters
#p_Param1 nvarchar(255)
)
CREATE PROCEDURE [dbo].[usp_GetByParam2]
(
-- Pagination
#p_Offset int,
#p_FetchNext int,
-- Filters
#p_param2 uniqueidentifier
)
CREATE PROCEDURE [dbo].[usp_GetByParam3]
(
-- Pagination
#p_Offset int,
#p_FetchNext int,
-- Filters
#p_param3 uniqueidentifier
)
Solution 3
Another way?
I think Solution 1 is the best one: it allows you to filter using one or more parameters: you can set a default value for your params, or pass null values when you do not want to filter by a certain parameter. Then the filter query could be written in this way:
SELECT
--your output
FROM
Table t
WHERE
--some conditions AND
( #p_Param1 is null OR t.column1 = #p_Param1 ) AND
( #p_Param2 is null OR t.column2 = #p_Param2 ) AND
( #p_Param3 is null OR t.column3 = #p_Param3 )
Solution 2 would require a lot of new procedures if you wanted to add more filter options or, for example, filter by parameters 2 and 3 at the same time.

How to insert multiple rows - a loop needed?

I have the following statement:
insert into forecast_entry.user_role_xref
( user_master_id ,
role_id ,
created_date ,
created_by
)
values
( 276 , -- user_master_id - int
101 , -- role_id - int
getdate() , -- created_date - datetime
'MICHAELSK' -- created_by - varchar(20)
)
I need to generate a row for role_id 101-355 (so the same statement above, except repeated with the role_id incrementing). What would be the best way to do this? To get the job done I'm intending on writing a quick C# application that will have a loop but I'm sure this isn't the best way and hope to learn something here to avoid having to do that in future (as I'm sure this kind of scenario is common).
Here is what I use, just modify as needed. Here, I add a bunch of sequence numbers to a table using a loop variable:
USE MyDB
GO
DECLARE #MyCounter as INT
SET #MyCounter = 1 -- to use this multiple times you can just
-- change the starting number and run again
-- if you do not want duplicate numbers
WHILE #MyCounter < 1000 -- any value you want
BEGIN
INSERT INTO [MyDB].[dbo].[MyTable]
([NumberField])
VALUES
(#MyCounter) -- insert counter value into table
set #MyCounter = #MyCounter + 1; -- increment counter
END
You should make use of numbers table and if you don't have one you can use master..spt_values like this:
insert into forecast_entry.user_role_xref
( user_master_id ,
role_id ,
created_date ,
created_by
)
select 276, -- user_master_id - int
number, -- role_id - int
getdate() , -- created_date - datetime
'MICHAELSK' -- created_by - varchar(20)
from master..spt_values
where type = 'P' and
number between 101 and 355
In my opinion, the best way is to create stored procedure. In stored procedure you should make a loop, which would insert data into table. From your C# application you open a connection to DB, call once a stored procedure and close a connection.
On SQL you get best perfomance working with big amount of data.
Here is an example
Instead of looping query Create a DataTable and create a stored procedure with User Defined Table Type
CREATE TYPE dtl AS TABLE
(
user_master_id INT ,
role_id INT,
created_date DATETIME,
created_by varchar(20)
)
And Stored procedure
CREATE PROCEDURE SPNAME
#dtl dtl READONLY
AS
INSERT INTO forecast_entry.user_role_xref
( user_master_id ,
role_id ,
created_date ,
created_by
)
SELECT
user_master_id ,
role_id ,
created_date ,
created_by
FROM #dtl
Pass DatatTable for #dtl parameter of stored procedure which contains the proper data between 101-255
if you create a loop in c# it will send same query again and again to database which is not a good idea.you rather create sp and loop there. as suggested by sham