Insert results of a table into stored procedure as parameters - sql

I have a stored procedure which inserts values into a table.
Let's say its name is usp_InsertTableA with parameters #ID int and Name varchar(100).
I have a requirement to call this stored procedure multiple times from another stored procedure. I am thinking to call this stored procedure something like below
exp usp_InsertTableA
select ID, Name from #tempTable
Is this possible in SQL Server to execute this with the value of the table and send it into a stored procedure?

You can use table type parameters to stored procedure.
CREATE TYPE [dbo].[udt_MyCustomTable] AS TABLE(
[id] [int] NOT NULL,
[name] [nvarchar](100) NOT NULL
)
GO
And then you stored procedure would be:
CREATE PROC [dbo].[usp_InsertTableA]
(
#myCustomTable udt_MyCustomTable READONLY
)
AS
BEGIN
-- Your code goes in here
END

Is this possible in SQL Server to execute this with the value of the table and send it into a stored procedure?
No, not with the stored procedure you have there. There are ugly hacks that could make it happen, but it's not how you're supposed to do things in T-SQL. Everything you do in SQL Server is supposed to be optimized to work on a set of rows, not a single row / row by row
In practice what this means is, if you have a query like this that produces 100 rows:
select ID, Name from #tempTable
You would pass those 100 rows to your insert procedure and insert them in one operation:
--expanding on sam's advice
--create a type
CREATE TYPE [dbo].[udt_MyCustomTable] AS TABLE(
[id] [int] NOT NULL,
[name] [nvarchar](100) NOT NULL
)
--your insert procedure
CREATE PROC [dbo].[usp_InsertTableA]
(
#myCustomTable udt_MyCustomTable READONLY
)
AS
BEGIN
INSERT INTO TableA(idcolumn, namecolumn)
SELECT is, name FROM #myCustomTable
END
Now in your main sp that wants to insert 100 rows:
#DECLARE tmpVar udt_MyCustomTable;
--put 100 rows into table variable
INSERT INTO tmpVar(id,name)
select ID, Name from #tempTable
--pass 100 rows in variable to SP to insert all at once
EXECUTE usp_InsertTableA tmpVar

DECLARE #ID INT, #Name VARCHAR(255)
SELECT #ID = ID, #Name=Name FROM #tempTable -- assumes one record in the table.
EXEC dbo.usp_insertdata #id, #Name

Related

Get the inserted row causing the execution of the trigger

I want to get the value of the row causing the execution of the trigger. So I can pass it (as a parameter) to a stored procedure.
The stored procedure accepts as input a table type which is defined in the script below:
CREATE TYPE PersonTableType AS TABLE
(
Id int primary key,
FirstName nvarchar(50),
LastName nvarchar(50)
)
The procedure (insert in the ArchivePerson table the inserted row from the trigger)
Create PROCEDURE sp1
#PersonType PersonTableType Readonly
As
BEGIN
Insert Into ArchivePerson
Select * From #PersonType
END
How do I declare my trigger?
I tried something like:
Alter TRIGGER insertPerson
ON Person
AFTER Insert
AS
BEGIN
declare #PersonType PersonTableType;
??
Exec sp1 #PersonType
END
The inserted table has the rows which were, well, inserted. It has the same columns with your original [Person] table, so use the appropriate columns:
Alter TRIGGER insertPerson
ON Person
AFTER Insert
AS
BEGIN
declare #PersonType PersonTableType;
insert #PersonType(Id,FirstName,LastName)
select <corresponding columns>
from inserted
Exec sp1 #PersonType
END

Select specific columns from the stored procedure

I have a stored procedure in other database which is maintained by other team. Assume that it is currently returning 3 columns, and my system only needs those 3 columns
but the other team can add few more columns for their own use which is causing my system to fail.
Other database SP
ALTER PROCEDURE FirstSP
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #A (Id INT, Name VARCHAR(200), Amount VARCHAR(100), TestColumn INT)
INSERT INTO #A VALUES
(1,'ABC','23',1), (2,'CDF','35454',2), (3,'hjhj','9809909',3)
SELECT * FROM #A
DROP TABLE #A
END
GO
And below is my query, which was only expecting 3 columns from the source
CREATE TABLE #MyTable (Id INT, Name VARCHAR(200), Amount INT)
INSERT INTO #MyTable
EXEC dbo.FirstSP;
SELECT * FROM #MyTable
DROP TABLE #MyTable
Is there any way I can provide the column list?
This is what I am trying but it seems that I can't use server name as the parameter
DECLARE #ServerName VARCHAR(100) = ##SERVERNAME
SELECT * FROM OPENQUERY(#ServerName,'EXEC dbo.FirstSP')
My whole problem is to just select required columns from the SP. SP can have many columns in future.
Try this:
/*
-----------------------------------------------------------------------
Replace <SERVERNAME>\<INSTANCENAME>], <DATABASENAME> with your names
*/ ------------------------------------------------------------------------
-- First, enable Data Access (One time only)
EXEC sp_serveroption '<SERVERNAME>\<INSTANCENAME>', 'DATA ACCESS', TRUE;
-- Then SELECT just the fields you need
SELECT ID, Name, Amount
FROM OPENQUERY([<SERVERNAME>\<INSTANCENAME>], 'EXEC <DATABASENAME>.dbo.FirstSP')
I would ask the team that develops the stored procedure to create a parameter "Team" or something and slightly change the sp so that it will return the expected columns based on this parameter.
A more cumbersome solution is to use this stored procedure the get the colum names of the (first) result returned by the sp.
sp_describe_first_result_set 'dbo.usp_mySp';
And then use the result to create some dynamic SQL.

Pass user-defined table type "on the fly" into stored procedure

If I have a stored procedure that uses a user-defined table as one of its inputs, is there any way to call the stored procedure without declaring the variable beforehand?
i.e. I have this type:
CREATE TYPE [IDs] AS TABLE
(
[ID] [BIGINT] NULL
)
and this procedure
CREATE PROCEDURE spDoSomething (#IDs IDs)
AS
...
Normally, this would be called by declaring the table variable first:
DECLARE #IDs IDs
INSERT #IDs VALUES (1),(2)
EXEC spDoSomething #IDs
Is there any way to call this in one line, i.e.
EXEC spDoSomething #IDs = (SELECT 1 AS ID UNION ALL SELECT 2)
Use case is that I am accessing the database through a UI, which builds the SQL dynamically and doing a DECLARE #IDs... is not possible

Can a table valued parameter to stored procedure have default values

Suppose that I have a two column User Defined Table type
CREATE TYPE [Schema].[Type] AS TABLE (
[Name] NVARCHAR (100) NULL
[Value] int NULL
);
Further suppose that I have stored procedure that I pass the table type to
CREATE PROCEDURE [Schema].[sp_SomeProcedure]
#TVP [Type] READONLY
AS
SELECT
[Name]
,1 + [Value]
FROM
#TVP
Can I default the value of #TVP to be
(SELECT 'John', 1)
You can use the 'DEFAULT' keyword for the TVP when calling the procedure. That will pass an empty table of the type.
Example - if the TVP is the second parameter passed to a procedure:
Exec myProcedure (intParam, DEFAULT)
SQL Server does not allow to make a TVP an optional parameter but setting some sort of default value to it, if you have a TVP in your procedure you will need to pass a TVP at runtime.
But there is a way around to it, add another parameter to your procedure which decides the behavior of TVP in your procedure.
Mind you in any case you would need to pass a TVP to your procedure at runtime.
CREATE PROCEDURE [Schema].[sp_SomeProcedure]
#TVP_Default BIT = 1
,#TVP [dbo].[Test_Type] READONLY
AS
BEGIN
DECLARE #tempTable TABLE (
[Name] NVARCHAR(100) NULL
,[Value] int NULL
);
-- If #TVP_Default = 1 default values will be populated
-- else values passed to TVP will be used
IF (#TVP_Default = 1)
BEGIN
INSERT INTO #tempTable([Name] , [Value])
SELECT 'John' , 1
END
ELSE
BEGIN
INSERT INTO #tempTable([Name] , [Value])
SELECT [Name]
,1 + [Value]
FROM #TVP
END
/*
rest of the code
use #tempTable instead of the TVP in rest of the code
*/
END

How to exec a stored procedure for each row in a select statement?

I have a stored procedure that returns an unique Id. I need to call this sp to get the unique ID for each row. I must use this SP because an application also uses this.
How can I select for each row a ID that is returned from the SP?
CREATE procedure [dbo].[SelectNextNumber]
#TableName nvarchar(255)
as
begin
declare #NewSeqVal int
set NOCOUNT ON
update Number --This is a table that holds for each table the max ID
set #NewSeqVal = Next = Next + Increase
where TableNaam= #TableName
if ##rowcount = 0
begin
Insert into Number VALUES (#TableName, 1, 1)
return 1
end
return #NewSeqVal
The number table:
CREATE TABLE [dbo].[Number](
[TableName] [varchar](25) NOT NULL,
[Next] [int] NULL,
[Increase] [int] NULL
I have seen that a While loop is usable for this but in my situation I don't know how to use a while loop.
You can't use stored procedures inside a SELECT statement, only functions.
You can iterate on a resultset with a cursor if you really have to use a stored procedure:
http://msdn.microsoft.com/library/ms180169.aspx
EDIT:
To be honest I'm not very sure to have understood what you really need, it looks like you are building a IDENTITY by yourself ( http://msdn.microsoft.com/library/ms174639(v=sql.105).aspx );
still, if you really need to run a cursor here's an example which uses your stored procedure:
http://sqlfiddle.com/#!3/2b81a/1
Taking the singular INSERT INTO.. SELECT apart:
Temporarily store the SELECT results away
declare #rc int, #NewSeqVal int;
SELECT ..
INTO #tmp -- add this
FROM ..
Store the rowcount and get that many numbers
set #rc = ##rowcount;
For which you have to use the code in the SP directly:
update Number --This is a table that holds for each table the max ID
set #NewSeqVal = Next = Next + #rc
where TableNaam= 'sometbl';
Finally, the insert
INSERT ...
SELECT ID = #NewSeqVal + 1 - row_number() over (ORDER BY col1)
, {all the other columns}
FROM #tmp;
ORDER by Col1 is arbitrary, choose something sensible, or make it ORDER BY NEWID() if you don't care.