TSQL: Using 'Output' clause in dynamic SQL - sql

I'm using an Output clause in my Insert statement which requires use of a Table Variable. I also want the Table name to be dynamic so I'm using dynamic SQL but it won't allow use of a Table Variable. I get the error Must declare the scalar variable "#InsertedId".
CREATE PROCEDURE sp_InsertPerson #Name varchar(50), #Table varchar(20) AS
DECLARE #InsertedId TABLE (Id int)
DECLARE #SQL nvarchar(200) = 'INSERT INTO ' + #Table + ' (Name) OUTPUT INSERTED.Id INTO ' + #InsertedId + ' VALUES (' + #Name + ')'
IF (#Name is not null AND #Name != '')
EXEC(#SQL)
SELECT Id FROM #InsertedId
How can I both use the Output clause and a dynamic Table name

First of all, do not use sp_ prefix to your stored procedure, cause it reserved to System stored procedures by MS, and can lead to performance issue and other problems (as it can be a habit). Use SysName datatype for the table name, and use QUOTENAME() function when you concatenate the string.
You need to declare your table in the DynamicSQL as
CREATE PROCEDURE InsertPerson
#Name varchar(50),
#Table SysName
AS
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N'DECLARE #IDs TABLE (ID INT);'+
'INSERT INTO ' +
QUOTENAME(#Table) +
' (Name) OUTPUT INSERTED.ID INTO #IDs VALUES(#Name);'+
'SELECT * FROM #IDs';
EXECUTE sp_executesql #SQL,
N'#Name VARCHAR(50)',
#Name;
Demo

Try this;
CREATE PROCEDURE sp_InsertPerson #Name varchar(50), #Table varchar(20) AS
DECLARE #SQL nvarchar(200) = ''
SET #SQL = #SQL + 'DECLARE #InsertedId TABLE (Id int)';
SET #SQL = #SQL + 'INSERT INTO ' + #Table + ' (Name) OUTPUT INSERTED.Id INTO #InsertedId (Id) VALUES (''' + #Name + ''')'
SET #SQL = #SQL + 'SELECT Id FROM #InsertedId'
IF (#Name is not null AND #Name != '')
EXEC(#SQL)

Related

Passing in table name and row info into an INSERT INTO stored procedure

I want to pass into the procedure the table name and the values without mentioning column names because I want to be able to use this on any table.
#row would be csv string like 'test','123'
My code causes an error:
CREATE PROCEDURE test
#table NVARCHAR(100),
#row NVARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX)
SET #sql = 'INSERT INTO ' + #table+ 'VALUES (' + #row + ')'
EXEC sp_executesql #sql
END
Please try this.
SQL
CREATE PROCEDURE test
#table NVARCHAR(100),
#row NVARCHAR(max)
AS
BEGIN
DECLARE #Sql NVARCHAR(MAX)
SET #sql = 'INSERT INTO [dbo].[' + #table+ '] VALUES (' + #row + ')'
EXEC sp_executesql #sql
END
Note: if you select table name dynamic and you are pass single values it means the table has single columns
If you pass any other table and table has multiple columns your insert statement not work.

T sql - How to store results from a dynamic query using EXEC or EXECUTE sp_executesql

I am trying to write a dynamic query. Let's say i have a table like below, which represents the hierarchy level of a sales agent:
AgentNumber Level1Agent Level2Agent Level3Agent Level4Agent Level5Agent
1122334455 1122334499 1122334488 1122334477 1122334466 1122334455
I want to be able to dynamically select a level based on a specified agent. My EXECUTE statement seems to work correctly, but how do I get the result stored in a variable I can use later? Every answer I have found seems to only get me a success return variable, not the actual query result.
Below is my code:
DECLARE #level INT = 1;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
DECLARE #whereclause NVARCHAR(35) = CONCAT('WHERE AgentNumber = ',#agent);
DECLARE #qry NVARCHAR(300) = 'SELECT ' + #colname + ' FROM dbo.TABLE ' + #whereclause;
DECLARE #up NVARCHAR(10);
EXECUTE sp_executesql #qry, #up OUT
SELECT #up
The output of #up is NULL. If I change the last two lines to:
EXECUTE #up = sp_executesql #qry
SELECT #up
Now the output of #up is 0.
I want the output of 1122334499 and I need it stored in a variable that can later be used and inserted into a table.
Here is a fully functional example of how you can do this. Notice this is using a parameterized where clause and quotename around the column name in the dynamic sql to prevent sql injection.
if OBJECT_ID('tempdb..#Agents') is not null
drop table #Agents
create table #Agents
(
AgentNumber char(10)
, Level1Agent char(10)
, Level2Agent char(10)
, Level3Agent char(10)
, Level4Agent char(10)
, Level5Agent char(10)
)
insert #Agents
select '1122334455', '1122334499', '1122334488', '1122334477', '1122334466', '1122334455'
DECLARE #level INT = 3;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
declare #agentout char(10)
DECLARE #qry NVARCHAR(300) = 'SELECT #agent_out = ' + quotename(#colname) + ' FROM #Agents WHERE AgentNumber = #agentin';
EXECUTE sp_executesql #qry, N'#agentin char(10), #agent_out char(10) output', #agentin = #agent, #agent_out = #agentout output
select #agentout
You can try this :
DECLARE #level INT = 1;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
DECLARE #whereclause NVARCHAR(35) = CONCAT('WHERE AgentNumber = ',#agent);
DECLARE #qry NVARCHAR(300) = 'SELECT #agentout=' + #colname + ' FROM dbo.TABLE ' + #whereclause;
DECLARE #up NVARCHAR(10);
EXECUTE sp_executesql #qry, N'#agentout NVARCHAR(10) OUTPUT', #agentout=#up OUTPUT
SELECT #up
Create a variable table and makes your query insert the results you want there. Something like this:
declare #results table(field1 varchar(max), field2 varchar(max));
declare #sqlStatement varchar(max);
set #sqlStatement = 'insert into #results(field1, field2) select field1, field2 from table';
EXECUTE #sqlStatement;
select * from #results; --It will print the results from your sql statement!

T-SQL Create Table with Dynamically Named Database with sp_executesql

I am attempting to create a table in T-SQL using sp_executesql. The name of the database containing the table is dynamic.
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = '[MyDatabase' + CAST(#ID as nvarchar(10)) + '].[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max) = N''
SELECT #CreateTable =
N'
CREATE TABLE #TableName
(
ID int
)
'
EXECUTE sp_executeSQL #CreateTable, N'#TableName nvarchar(max)', #TableName = #TableName
This script results in this error:
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near '#TableName'.
What is the best way to specify the name of the table to create dynamically based on parameters of sp_executeSQL?
You cannot pass Tablename as a parameter even we using sp_executesql procedure. You have to build you own dynamic sql query
SELECT #CreateTable =
N'
CREATE TABLE ' + #TableName + '
(
ID int
)
'
Exec sp_executesql #CreateTable
When you are passing the table name as a parameter to sp_executesql, it treats it as a literal string, to make it treat it as an object name try something like this......
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = QUOTENAME('MyDatabase' + CAST(#ID as nvarchar(10)))
+ '.[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max);
SET #CreateTable = N' CREATE TABLE ' + #TableName
+ N' (
ID int
)'
Exec sp_executesql #CreateTable
EDIT
It is good practice to check if an object already exists before you try to create it.
You can check if the object already exists and drop it and then create the new one, you code should look something like.....
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = QUOTENAME('MyDatabase' + CAST(#ID as nvarchar(10)))
+ '.[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max), #DropTable nvarchar(max);
-- Drop table if already exists
SET #DropTable = N' IF OBJECT_ID('''+ #TableName +''') IS NOT NULL '
+ N' DROP TABLE ' + #TableName
Exec sp_executesql #DropTable
SET #CreateTable = N' CREATE TABLE ' + #TableName
+ N' (
ID int
)'
Exec sp_executesql #CreateTable

Can I use variable in condition statement as value with where condition that test that value

I have the following stored procedure:
ALTER proc [dbo].[insertperoll] #name nvarchar(50) , #snum int , #gnum int
as
DECLARE #value nvarchar(10)
SET #value = 's'+CONVERT(nvarchar(50),#snum)
DECLARE #sqlText nvarchar(1000);
DECLARE #sqlText2 nvarchar(1000);
DECLARE #sqlText3 nvarchar(1000);
declare #g nvarchar(50) = '''g1'''
SET #sqlText = N'SELECT ' + #value + N' FROM dbo.GrideBtable'
SET #sqlText2 = ' where Gnumber = '+#g --here is the problem it error invalid column name -- the #g is value from the table condition
set #sqlText3 = #sqlText+#sqlText2
Exec (#sqlText3) -- here how can i save the result of the exec into varibale
declare #sal nvarchar(50) = #sqlText3
insert employ (name,Snumber,Gnumber,Salary) values(#name,#snum,#gnum,#sal)
QUESTION: How to put in condition variable gets value from the table when i exec it it think that the #g is column but its not its a value from the table to test it so i display one value after the exec the other QUESTION is how to save the result from the exec in variable and then use that value
I'm using SQL Server 2008 (9.0 RTM)
This will be a stored procedure
Thanks in advance
Not sure why you would go through all the loops to insert into the table where you can have a simple insert query like ..
ALTER PROC dbo.[insertperoll] #name nvarchar(50) , #snum int , #gnum int
AS
insert employ (name, Snumber, Gnumber, Salary)
select #name
, #sum
, #gnum
, case when #snum = 1 then s1
when #snum = 2 then s2
when #snum = 3 then s3
when #snum = 4 then s4
end as Salary
from dbo.GrideBtable
where Gnumber = #gnum
If your intent is to have the proc retrieve a salary value from a column determined from the parameter snum and then make an insert into employ using the values passed as parameters and the salary retrieved I think you could refactor your procedure to this:
CREATE proc [dbo].[insertperoll] #name nvarchar(50) , #snum int , #gnum int AS
DECLARE #g NVARCHAR(50) = 'g1'
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'INSERT employ (name,Snumber,Gnumber,Salary) '
SET #sql += N'SELECT ' + QUOTENAME(#name, '''')
SET #sql += N', ' + CAST(#snum AS NVARCHAR(50))
SET #sql += N', ' + CAST(#gnum AS NVARCHAR(50))
SET #sql += N', s' + CAST(#snum AS NVARCHAR(50))
SET #sql += N' FROM dbo.GrideBtable'
SET #sql += N' WHERE Gnumber = ' + QUOTENAME(#g, '''')
EXEC (#sql)
Of course you could add the #g variable to the procedure parameters instead of having it hard coded in the procedure and call it as:
EXEC insertperoll #name='john', #snum=10, #gnum=100, #g='g1'
Sample SQL Fiddle (with some assumptions made about table structure)
You could do this using sp_executesql instead of exec() since this will allow you to use parameters, you can use an output parameter to get the value from the query:
DECLARE #SQL NVARCHAR(MAX) = N'SELECT #val = ' + CONVERT(NVARCHAR(10),#snum) +
N' FROM dbo.GrideBtable WHERE Gnumber = #G1';
DECLARE #val INT; -- NOT SURE OF DATATYPE REQUIRED
EXECUTE sp_executesql #SQL, N'#G1 VARCHAR(20), #val INT OUT', 'G1', #val OUT;

Must declare the scalar variable with Table-Valued Parameters and Stored Procedure

Could someone explain why the following gives me "Must declare the scalar variable #facilities." but works fine if I were to use VARCHAR instead of my created type? How can I fix this?
TIA
--CREATE TYPE integer_list AS TABLE (n int NOT NULL PRIMARY KEY)
--DROP PROCEDURE spTestTVP
CREATE PROCEDURE spTestTVP (
#facilities integer_list READONLY
--#facilities varchar(100)
)
AS
DECLARE #sql nvarchar(4000)
SET #sql = 'SELECT * FROM TestTable'
SET #sql = #sql + ' WHERE 1=1 '
IF #facilities IS NOT NULL
SET #sql = #sql + ' AND (FacilityNo IN (' + #facilities + ') OR FacilityNo IS NULL)'
EXEC sp_executesql #sql
DECLARE #items VARCHAR(MAX)
SELECT#items = COALESCE(#items+',' ,'') + n
FROM #facilities
DECLARE #sql nvarchar(4000)
SET #sql = 'SELECT * FROM TestTable'
SET #sql = #sql + ' WHERE 1=1 '
IF #facilities IS NOT NULL
SET #sql = #sql + ' AND (FacilityNo IN (' + #items + ') OR FacilityNo IS NULL)'
EXEC sp_executesql #sql
or not dynamic as follows:
SELECT t.* FROM TestTable as t
left outer join
#facilities as f
on
f.n = t.FacilityNo
where
t.FacilityNo is null
or
f.n is not null
When you are concatenating things in a dynamicSQl statment all pieces that build the statement must be either varchar or nvarchar. That is a limit of SQL.
On the other hand you don't need dynamic sql since you have created a table.
SELECT * FROM TestTable t
LEFT join #facilities f on f.n = t.facilityNO