Stored procedure return the primary key after insert? - sql

I want a stored procedure to return the primary key of the new record after it gets executed. I think it will be returned by OUT parameter in the procedure. But how to select the newly inserted row ID ? I don't want to use select MAX(row_id) as it is a multi user environment.
Any procedure sample will be appreciated.
My platform is ISeries DB2 V5 R4. Thanks.
Edit
The row id Column is not an identity column. It uses a sequence for the key which gets generated via a trigger before insert on table.
Edit
Here is what I am trying to do
Begin Stored procedure
Insert into Employees;
(row id gets automatically generated by trigger)
Return row id ;
I want to avoid a select in returning row id.

just set the out parameter to the column that contains the PK.
CREATE PROCEDURE DB2TBL.DO_STUFF (IN Param1 INT, IN Param2 CHAR(32),OUT Param3 INT)
/* Param1 is primary key */
LANGUAGE SQL
P1: BEGIN
DECLARE OUTPARAM INT;
/* Do the stored procedure */
SET OUTPARAM = Param1;

--UPDATED---
Hi Popo,
First off could you give more detail on what you mean when you say the rowid is assigned by a trigger?
If you had a real identity column you would use the IDENTITY_VAL_LOCAL() function like this right after the INSERT: SELECT IDENTITY_VAL_LOCAL() INTO myrowid FROM SYSIBM.SYSDUMMY1; I'm not 100% on that syntax because I generally use embedded SQL and it works differently there so you might have to play with it. IBM documentation is at http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/db2/rbafzscaidentity.htm.
However since you are doing something more complicated, I think this alternate method might work. You'll need to re-format your INSERT to be wrapped in a SELECT.
SELECT myrowid
INTO myrowid
FROM FINAL TABLE (
INSERT INTO myfile (myrowid, other_stuff) VALUES (default, 'blah')
)
You'll need to adjust for the proper field names and so on but I think this will do the trick. There's not much documentation but if you want to see it go to http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/db2/rbafzbackup.htm and scroll all the way down to the bottom of the page.
Cheers

CREATE PROCEDURE ASF_InsertNewAuthorRequest
(IN #REQUESTTYPE CHAR(1), IN #UserID VARCHAR(18), IN #DATECREATED TIMESTAMP, IN #REQUESTSTATUS CHAR(1))
LANGUAGE SQL
DYNAMIC RESULT SETS 1
P1: BEGIN
DECLARE cursor1 CURSOR WITH RETURN for
SELECT IDENTITY_VAL_LOCAL FROM SYSIBM.SYSDUMMY1;
INSERT INTO AFS_REQUEST
( REQUESTTYPE, "UserID", DATECREATED, REQUESTSTATUS )
VALUES
( #REQUESTTYPE, #UserID, #DATECREATED, #REQUESTSTATUS );
OPEN cursor1;
END P1

INSERT INTO [User] (columns)
OUTPUT inserted.userId
VALUES (#values)
This will return the newly created userId column value... very simple.

Related

Reading Table Type Output in HANA

How can I read the content of an out table type parameter of a procedure in SAP HANA SQL Script?
Sample Procedure:
create procedure "MYSCHEMA".ReturnTypeTest(out OUTPUT_TABLE "MYSCHEMA"."RESOUT")
as
begin
create local temporary table #temp ("COL1" bigint, "COL2" bigint, "COL3" bigint);
insert into #temp values(1, 2, 3);
insert into #temp values(4, 5, 6);
insert into #temp values(7, 8, 9);
OUTPUT_TABLE = select * from #temp;
drop table #temp;
end;
Table Type (Out Parameter):
create type "MYSCHEMA"."RESOUT" as table ("COL1" bigint, "COL2" bigint, "COL3" bigint);
When I call the procedure as below, it displays entire content in SAP HANA Studio's result pane but how can I get it programmatically?
call "MYSCHEMA"."RETURNTYPETEST"(?);
Output variables from procedures can only be assigned to variables in an SQLScript context.
An exception to this is the default resultset that gets bound to the last SELECT command executed in the procedure.
If your intention is to produce something that can be SELECTed, you may want to use a table typed user defined function (TUDF) instead.
Two comments to your example code:
using temporary tables is not a good idea if performance is of concern for your application. While imperative code often appears
to be more intuitive, it really tends to block parallelism during
statement execution.
It's very (too) easy to overload a single procedure function wise by including data manipulation, computation and resultset
returns. If possible, rather opt for smaller functional units and
split up the functionality into multiple objects.
Ok, after you clarified that you actually just want to access the resultset in SQLScript and not in plain SQL, I can add this to my answer:
Check what I wrote in the first sentence! You can simply assign any output variable from a procedure to a corresponding variable.
The documentation has examples on that HANA documentation: CALL.
For example, if your output structure is a table that contains user information it may look like this:
DECLARE uaccounts TABLE (USERID bigint, USERNAME NVARCHAR(256), CREATED date);
DECLARE expdate date := current_date;
/* In this example the procedure 'get_expired_useraccounts_by date' has got
the IN parameter expiry_date (date) and
the OUT parameter expired_accounts (table structure).
By assigning the variable uaccounts to the OUT parameter, the result set
automatically gets bound to uaccounts.*/
call get_expired_useraccounts_by_date (:expdate, :uaccounts);
/* from here you can use :uaccounts like a table variable*/
SELECT count(*) FROM :uaccounts;
All this is, of course, part of the reference documentation and the developer guides...
Could you please check following SQLScript
declare lt_list "MYSCHEMA"."RESOUT";
call "MYSCHEMA"."RETURNTYPETEST"(lt_list);
select * from :lt_list;
This should display the output parameter table using the last SELECT statement
The answer, after understanding the context with Lars' Q&A, is: define a table variable in your caller procedure code
DECLARE temp TABLE (n int);
DECLARE temp MY_TABLE_TYPE;
Then assign the output param of the callee to it.
https://help.sap.com/viewer/de2486ee947e43e684d39702027f8a94/2.0.01/en-US/ea5065d06d14426799d879234d8e3e7b.html
You can query the system views for metadata
Please check following SQLScript Select
select table_type_schema, table_type_name, *
from PROCEDURE_PARAMETERS
where
schema_name = UPPER('MYSCHEMA') and
procedure_name = UPPER('ReturnTypeTest') and
parameter_name = UPPER('OUTPUT_TABLE')
I hope it helps

Function for row insertion

I am relatively newbie with SQL Server, and I have some experience and practices from Oracle & PostgreSQL which i want to use in the SQL Server.
I need to create function which takes fields values for new row in the table and which also returning autogenerated ID value of the new record.
First of all I am faced with the fact that the functions in SQL Server can not change data in the tables. The second my discovery was that is the procedures in SQL Server can return values through return #result construction.
I investigate output mechanism of the DML queries, but they returns not scalar but table results.
Be patient and let me more clear. There is PostgreSQL function which doing what I want:
Table creation script:
create table foobar
(
foo bigint not null default nextval('s_foobar'::regclass),
bar character varying(16),
constraint pk_foobar primary key (foo)
);
and function script:
create or replace function f_foobar_insert(p_bar character varying)
returns integer as
$body$declare
result integer;
begin
insert into foobar(bar) values (p_bar) returning foo into result;
return result;
end;$body$ language plpgsql;
Is there any possibility to make something like this in SQL Server in the same way?
In SQL Server, the table creation would be:
create table foobar
(
foo bigint not null identity primary key,
bar varchar(16)
);
The following is one way in SQL Server to get the functionality:
insert into foobar(bar) select 'value';
select ##identity;
This is not really the preferred way. You should really use the output clause:
declare #t table (foo bigint);
insert into foobar(bar)
output inserted.foo into #t
select 'value';
select foo from #t;
You can wrap this in a stored procedure if you like, but it doesn't seem necessary, and stored procedures have different semantics from functions.

How to selectively return rows inside a stored procedure on SQL Server?

I have a base stored procedure simply returning a select from the database, like this:
CREATE PROCEDURE MyProcedure
AS
BEGIN
SELECT * FROM MyTable
END
GO
But now I need to execute some logic for every row of my select. According to the result I need to return or not this row. I would have my select statement running with a cursor, checking the rule and return or not the row. Something like this:
CREATE PROCEDURE MyProcedure
AS
BEGIN
DECLARE CURSOR_MYCURSOR FOR SELECT Id, Name FROM MyTable
OPEN CURSOR_MYCURSOR
FETCH NEXT FROM CURSOR_MYCURSOR INTO #OUTPUT1, #OUTPUT2
WHILE (##FETCH_STATUS=0)
BEGIN
IF (SOME_CHECK)
SELECT #OUTPUT1, #OUTPUT2
ELSE
--WILL RETURN SOMETHING ELSE
END
END
GO
The first problem is that everytime I do SELECT #OUTPUT1, #OUTPUT2 the rows are sent back as different result sets and not in a single table as I would need.
Sure, applying some logic to a row sounds like a "FUNCTION" job. But I can't use the result of the function to filter the results being selected. That is because when my check returns false I need to select something else to replace the faulty row. So, I need to return the faulty rows so I can be aware of them and replace by some other row.
The other problem with this method is that I would need to declare quite a few variables so that I can output them through the cursor iteration. And those variables would need to follow the data types for the original table attributes and somehow not getting out of sync if something changes on the original tables.
So, what is the best approach to return a single result set based on a criteria?
Thanks in advance.
I recommend use of cursors but easy solution to your question would be to use table variable or temp table
DECLARE #MyTable TABLE
(
ColumnOne VARCHAR(20)
,ColumnTwo VARCHAR(20)
)
CREATE TABLE #MyTable
(
ColumnOne VARCHAR(20)
,ColumnTwo VARCHAR(20)
)
than inside your cursors you can insert records that match your logic
INSERT INTO #MyTable VALUES (#Output1, #Output2)
INSERT INTO #MyTable VALUES (#Output1, #Output2)
after you done with cursor just select everything from table
SELECT * FROM #MyTable
SELECT * FROM #MyTable

Stored Procedure - Knowing the next ID

I am creating a stored procedure to create a new customer so for instance,
CREATE PROCEDURE Customer_Create
#customer_arg
#type_arg
AS
BEGIN
INSERT INTO Customer (Customer_id, Type_id)
VALUES (#Customer_arg,#type_arg)
End;
If I have several foreign keys in my statement and they are all ID's is there a way for me to pull the NEXT ID number automatically without having to know what it would be off the top of my head when I run the execute statement? I would like to just have it pull the fact that the ID will be 2 because the previous record was 1
EXECUTE Customer_Create 16,2
Is it something wnith output? If so how does this work code wise
I suspect that what you want to do is return the new id after the record is inserted. For that:
CREATE PROCEDURE Customer_Create (
#customer_arg,
#type_arg,
#NewCustomerId int output
) AS
BEGIN
INSERT INTO Customer(Customer_id, Type_id)
VALUES (#Customer_arg, #type_arg);
#NewCustomerId = scope_identity();
End;
There are several other choices for getting the identity, which are explained here.
To get to the last inserted IDENTITY value you should use the OUTPUT clause like this:
DECLARE #IdentValues TABLE(v INT);
INSERT INTO dbo.IdentityTest
OUTPUT INSERTED.id INTO #IdentValues(v)
DEFAULT VALUES;
SELECT v AS IdentityValues FROM #IdentValues;
There are several other mechanisms like ##IDENTITY but they all have significant problems. See my Identity Crisis article for details.
In your case you can also experiment with #IDENTITY like this
DECLARE #NextID int
--insert statement goes here
SET #NextID = ##Identity`
Here are couple good resources for getting familiar with this
http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
http://blog.sqlauthority.com/2013/03/26/sql-server-identity-fields-review-sql-queries-2012-joes-2-pros-volume-2-the-sql-query-techniques-tutorial-for-sql-server-2012/

Inserting multiple rows with SQL where a record does not exist

I want to insert multiple rows of data into a MySQL database, but only when my order_id field is unique. This is the current query I have, which doesn't work. Lets say a record with an order_id of 2 is already in the table:
INSERT INTO conversion
(user_id,url_id,order_id,sale,commission,transaction_date,process_date)
VALUES (1,1,1,'32',0.3995,'2010-11-15 12:15:18','2010-11-15 12:15:18'),
(3,6,2,'*not-available*',0.001975,'2010-11-15 12:15:18','2010-11-15 12:15:18')
WHERE (order_id <> 3);
Any help is appreciated.
Tom
Solved by using REPLACE.
Example:
REPLACE INTO conversion (user_id,url_id,order_id,sale,commission,transaction_date,process_date) VALUES (1,1,3,'32',0.3995,'2010-11-15 12:50:31','2010-11-15 12:50:31'),(1,2,2,'*not-available*',0.001975,'2010-11-15 12:50:31','2010-11-15 12:50:31');
url: http://dev.mysql.com/doc/refman/5.0/en/replace.html
Thanks all.
INSERT doesn't support the WHERE clause because if you're inserting it implies that the record doesn't currently exist, so therefore there would be nothing for the WHERE clause to look at.
The way to do it in the example you've given is simply not to call the INSERT statement if the order_id field in your insert doesn't match the criteria you want.
If you're calling INSERT multiple times, you'd have some sort of code (either SQL or an external program) which loops through the rows you're inserting; this would be where you'd filter it.
If I am in a similar situation, I would create a stored procedure to handle the logic of figuring out whether an order_id already exists.
--Run this first
--It will create a stored procedure call InsertConversion
--Begin of stored procedure
CREATE PROCEDURE InsertConversion
#user_id int,
#url_id int,
#order_id int,
#sale varchar(5),
#commission money,
#transaction_date datetime,
#process_date datetime
AS
BEGIN
SET NOCOUNT ON;
if not exists(select order_id from conversion where order_id = #order_id)
begin
INSERT INTO conversion(user_id, url_id, order_id, sale, commission, transaction_date, process_date)
VALUES(#user_id, #url_id, #order_id, #sale, #commission, #transaction_date, #process_date)
end
END
GO
--End of stored procedure
Once the store procedure created, you can execute it and pass in the same values as you would pass into an INSERT/VALUES statement:
exec InsertConversion 1,1,1,'32',0.3995,'2010-11-15 12:15:18','2010-11-15 12:15:18'
exec InsertConversion 3,6,2,'*not-available*',0.001975,'2010-11-15 12:15:18','2010-11-15 12:15:18'
If you want to be fancy, you can include a couple of 'print' statement in the store procedure to tell you whether it inserts the record.