I've been searching for hours on how to execute the statements I have stored in a table that has the results of a SELECT statement.
I have found similar questions but none of them works.
So now I have a table where the first column's cells contain
DROP TABLE table1
DROP TABLE table2
..... and so on.
I've tried using the EXEC command but I can't make it work.
Please help. Thank you.
I think you need to implement a cursor if you want to execute all statements
DECLARE #Query VARCHAR(250)
DECLARE crs_ExecStatement CURSOR FAST_FORWARD
FOR
SELECT Column1 FROM YourTable
OPEN crs_ExecStatement
FETCH NEXT FROM crs_ExecStatement INTO #Query
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC(#Query)
FETCH NEXT FROM crs_ExecStatement INTO #Query
END
CLOSE crs_ExecStatement
DEALLOCATE crs_ExecStatement
use EXEC and separate the values with GO as next demo:-
Create database Demo
go
use Demo
go
Create table MyTable (Value varchar (200))
go
insert into MyTable values ('Drop Table table1')
go
insert into MyTable values ('Drop Table table2')
go
insert into MyTable values ('Drop Table table3')
go
declare #Query nvarchar(max)
SELECT #Query = isnull(#Query,'') + Value + char (10) + 'Go'
FROM MyTable
--print #Query
SET #Query = 'EXEC (''' + REPLACE(REPLACE(#Query, '''', ''''''), 'GO', '''); EXEC(''') + ''');'
EXEC (#Query)
The idea of executing dynamic Query with go is taken from here.
Related
I'm trying to insert all records from tableA to tableB. TableA exists, TableB does not.
Here is my stored procedure. This code works but it's limited to a fixed table name tableB:
USE [myDatabaseName]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[myStoreProcedureFileName]
AS
BEGIN
SELECT *
INTO tableB
FROM tableA
END
However, I want to make tableB as a variable so I can pass it from C# code, this doesn't work, please help:
ALTER PROCEDURE [dbo].[myStoreProcedureFileName]
#tableName varchar(32)
AS
BEGIN
SELECT *
INTO #tableName
FROM tableA
END
Please help - why is SQL Server not recognizing #tableName in the select line? Solutions?
You need to use dynamic SQL:
ALTER PROCEDURE [dbo].[myStoreProcedureFileName] (
#tableName varchar(32)
) AS
BEGIN
DECLARE #sql NVARCHAR(MAX) = 'SELECT * into #tableName from tableA';
SET #sql = REPLACE(#sql, '#tableName', #tableName);
EXEC sp_executesql #sql;
END;
Parameters can only replace constants in a SQL statement. They cannot replace identifiers, operators, function names, or keywords.
You must use dynamic SQL
declare #sql nvarchar(max);
set #sql = N'select * into ' + #tableName + N' from tableA';
exec sp_executesql #sql;
I'm trying to insert rows from one table into another using a trigger with declared variable. When I run the code separately, it works for insert, but I want to create a trigger and return 0 rows
This is what I tried
CREATE TRIGGER Final
ON schedule
FOR INSERT
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql = 'INSERT INTO Datatable (Name, SAP_ID, Enterprise_IDs, Queue,d)
SELECT Name, SAP_ID, Enterprise_IDs, Queue, [' +
CONVERT(NVARCHAR(MAX), DAY(GETDATE())) + '] AS d
FROM schedule'
EXEC (#sql)
END
I expect the rows must be inserted into another table, but 0 rows are getting inserted
My guess is that the schedule is empty. You don't want to insert the rows from schedule. You want to use inserted instead:
CREATE TRIGGER Final ON schedule
FOR INSERT
AS
begin
declare #sql nvarchar(max);
set #sql = N'
insert into Datatable(Name, SAP_ID, Enterprise_IDs,Queue,d)
select Name, SAP_ID, Enterprise_IDs, Queue, [#d]
from inserted
';
set #sql = replace(#sql, '#d', day(getdate());
exec sp_executesql #sql;
end;
go
Having written this, I'm not sure if inserted is allowed in dynamic SQL.
I don't see why you need to use dynamic query, when you can just do it as below?
CREATE TRIGGER Final
ON schedule
FOR INSERT
AS
BEGIN
INSERT INTO Datatable (Name, SAP_ID, Enterprise_IDs, Queue,d)
SELECT Name, SAP_ID, Enterprise_IDs, Queue, CONVERT(NVARCHAR(MAX),DAY(GETDATE()))
FROM inserted
END
UPDATE
just by executing this part
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT [' + convert(nvarchar(max),day(getdate())) + '] AS d '
print #sql
EXEC (#sql)
you will see that your script is throwing an error as [9] (if we consider todays date) is invalid column, sql engine thinks its a column from your table schedule, get rid of the brackets and it should work fine
Is something like this possible?:
DECLARE #test nvarchar(30) = 'Appt'
SELECT * FROM #test.dbo.tablename with (NOLOCK)
or possibly
DECLARE #test nvarchar(30) = 'Appt'
SELECT * FROM #test + '.dbo.tablename' with (NOLOCK)
No, right?
I'm not looking to put the whole string into a variable and then use "EXEC." I have long scripts that I want to just try to replace that with when it occurs.
Thank you.
This requires Dynamic SQL. Basically you create a string that builds the SQL statement dynamically based on your query. That string is then executed with an EXEC Statement. A basic example is like this:
DECLARE #test nvarchar(30) = 'Appt'
DECLARE #sql as varchar(max)
SET #SQL = 'SELECT * FROM' + #test + '.dbo.tablename' + 'with (NOLOCK)'
EXEC #SQL
Assuming your tablename was Appt.dbo.tablename
I think you meant:
SET #SQL = 'SELECT * FROM' + 'dbo.' + #test + ' with (NOLOCK)'
Nice explanation logixologist.
Because Tom wants to run it for multiple select statements, i was thinking he could store all the table names in a column and use a cursor to fetch the table values. Considering you would create a table first such as:
CREATE TABLE tableName ( name varchar(20));
then run the following code once you inserted the right values in the table above.
Declare #table VARCHAR(255)
DECLARE #sql as varchar(max)
SET #SQL = 'SELECT * FROM' + 'dbo.' + #table + ' with (NOLOCK)'
DECLARE table_cursor CURSOR FOR
select distinct([name]) FROM DBname.dbo.tableName
Where [name] is not null
OPEN table_cursor
FETCH Next from table_cursor
INTO #table
WHILE ##FETCH_STATUS =0
BEGIN
EXEC #SQL
FETCH NEXT FROM table_cursor
INTO #table
END
CLOSE table_cursor
DEALLOCATE table_cursor
The cursor would return the table name for the select statement. I think you could use the same logic for insert statements.
I am creating stored procedure in which I need to build a temporary table dynamically. I tried the following code but its not creating table. When I execute the generated Query in Query window it works fine there.
--declare query variable
DECLARE #Query nvarchar(MAX)
SET #Query = 'CREATE TABLE #final (DATE int,'
--DECLARE #COLUMNNAME VARIABLE
DECLARE #ColName nvarchar(10)
OPEN #taCur
FETCH NEXT FROM #taCur INTO #ColName
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #Query = #Query + 'T_' + #ColName +' int,'
FETCH NEXT FROM #taCur INTO #ColName
END
SET #Query = #Query + 'TOTAL int,CUMM_TOTAL int)'
print #Query
EXEC sp_executesql #Query
--SET #Query = 'INSERT INTO #final (DATE) VALUES (1)'
SET #Query = 'SELECT * FROM #final'
print #Query
EXEC(#Query)
Final generated create table Query is as follow
CREATE TABLE #final (DATE int,T_211E int,T_211G int,T_211H int,T_211J int,T_211L int,T_221F int,TOTAL int,CUMM_TOTAL int)
Object #final used in CREATE and SELECT statements is not in the same scope.
Here is one way to structure the query.
Try to terminate SQL statements with semicolon. Even though it is not mandatory, it will help you differentiate the statements for readability. Note that I have included semicolon at the end of CREATE, INSERT and SELECT statements.
You can notice that CREATE, INSERT and SELECT are executed in the same transaction. Thereby, you don't lose the scope of the temporary table.
Script:
CREATE TABLE dbo.ColumnSchema
(
ColName NVARCHAR(10)
);
INSERT INTO dbo.ColumnSchema (ColName) VALUES
('211E'),
('211G'),
('211H'),
('211J'),
('211L'),
('211F');
DECLARE #Query NVARCHAR(MAX);
DECLARE #ColName NVARCHAR(10);
SET #Query = 'CREATE TABLE #final (DATE int,';
DECLARE taCursor CURSOR FOR
SELECT ColName
FROM dbo.ColumnSchema;
OPEN taCursor
FETCH NEXT FROM taCursor
INTO #ColName
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #Query = #Query + 'T_' + #ColName + ' int, '
FETCH NEXT FROM taCursor
INTO #ColName
END
CLOSE taCursor;
DEALLOCATE taCursor;
SET #Query = #Query + 'TOTAL int,CUMM_TOTAL int); '
SET #Query = #Query + 'INSERT INTO #final (DATE) VALUES (1); '
SET #Query = #Query + 'SELECT * FROM #final; '
EXEC (#Query);
Output:
DATE T_211E T_211G T_211H T_211J T_211L T_211F TOTAL CUMM_TOTAL
---- ------ ------ ------ ------ ------ ------ ----- ----------
1 NULL NULL NULL NULL NULL NULL NULL NULL
Your problem is that your temp table only exists within the scope that it is created... which is within the scope of your first sp_executesql. When you call your select statement, your temp table is no longer in scope.
To fix this, you would have to build up a single string that contains everything you need to do with your temp table: your create, insert, and select all within the a single sp_executesql call.
However, you should be aware that your current approach is likely vulnerable to SQL injection if you don't have complete control over all the values that are used to build up your commands.
Was trying to select...into a temp Table #TempTable in sp_Executedsql.
Not its successfully inserted or not but there Messages there written
(359 row(s) affected) that mean successful inserted?
Script below
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = 'select distinct Coloum1,Coloum2 into #TempTable
from SPCTable with(nolock)
where Convert(varchar(10), Date_Tm, 120) Between #Date_From And #Date_To';
SET #Sql = 'DECLARE #Date_From VARCHAR(10);
DECLARE #Date_To VARCHAR(10);
SET #Date_From = '''+CONVERT(VARCHAR(10),DATEADD(d,DATEDIFF(d,0,GETDATE()),0)-1,120)+''';
SET #Date_To = '''+CONVERT(VARCHAR(10),DATEADD(d,DATEDIFF(d,0,GETDATE()),0)-1,120)+''';
'+ #Sql;
EXECUTE sp_executesql #Sql;
After executed,its return me on messages (359 row(s) affected).
Next when trying to select out the data from #TempTable.
Select * From #TempTable;
Its return me:
Msg 208, Level 16, State 0, Line 2
Invalid object name '#TempTable'.
Suspected its working only the 'select' section only. The insert is not working.
how fix it?
Using a global temporary table in this scenario could cause problems as the table would exist between sessions and may result in some problems using the calling code asynchronously.
A local temporary table can be used if it defined before calling sp_executesql e.g.
CREATE TABLE #tempTable(id int);
execute sp_executesql N'INSERT INTO #tempTable SELECT myId FROM myTable';
SELECT * FROM #tempTable;
Local temporary table #table_name is visible in current session only, global temporary ##table_name tables are visible in all sessions. Both lives until their session is closed.
sp_executesql - creates its own session (maybe word "scope" would be better) so that's why it happens.
In your #sql string, don't insert into #TempTable. Instead, call your SELECT statement without an INSERT statement.
Finally, insert the results into your temporary table like so:
INSERT INTO #tmpTbl EXEC sp_executesql #sql
Also, you'll need to declare the temporary table if you use this approach
DECLARE #tmpTbl TABLE (
//define columns here...
)
your temp table in dynamic SQL is out of scope in the non dynamic SQL part.
Look here how to deal with this: A bit about sql server's local temp tables
Temporary tables only live as long as the connection that creates them. I would expect that you're unintentionally issuing the select on a separate connection. You can test this by momentarily doing your insert into a non-temporary table and seeing if your data is there. If that is the case you can go back to your original solution and just be sure to pass the connection object to your select.
declare #sql varchar(1000)
set #sql="select * into #t from table;"
set #sql =#sql + "select * from #t;"
execute SP_EXECUTESQL #sql
This worked for me
declare #sql nvarchar(max)
create table #temp ( listId int, Name nvarchar(200))
set #sql = 'SELECT top 10 ListId, Name FROM [V12-ListSelector].[dbo].[List]'
insert into #temp
exec sp_executesql #sql
select * from #temp
drop table #temp
To work around this issue use a CREATE TABLE #TEMPTABLE command first to generate an empty temp table before running sp_executesql. Then run the INSERT INTO #TEMPTABLE with sp_executesql. This will work. This is how I overcome this problem as I have a setup in which all my queries are usually run via sp_executesql.
This one worked for me:
DECLARE #Query as NVARCHAR(MAX);
SET #Query=(SELECT * FROM MyTable) ;
SET #Query=(SELECT 'SELECT * INTO dbo.TempTable FROM ('+#Query +') MAIN;');
EXEC sp_executesql #Query;
SELECT * INTO #TempTable FROM dbo.TempTable;
DROP TABLE dbo.TempTable;
SELECT * FROM #TempTable;
Note, from T-SQL 2021 onwards, dm_exec_describe_first_result_set() can be used to build a temporary table in the right shape to INSERT INTO - as it gives you the column names and types that will be returned from your dynamic SELECT or EXEC ... so you can build dynamic SQL to ALTER a temporary table into the shape you need.
DECLARE #strSQL NVarChar(max) = 'EXEC [YourSP] #dtAsAt=''2022-11-09'', #intParameter2=42'
--*** Build temporary table: create it with dummy column, add columns dynamically
--*** using an exec of sys.dm_exec_describe_first_result_set() and dropping the dummy column
DROP TABLE IF EXISTS #tblResults;
CREATE TABLE #tblResults ([zz] INT);
DECLARE #strUpdateSQL NVarChar(max);
SELECT #strUpdateSQL = STRING_AGG( CONCAT( 'ALTER TABLE #tblResults ADD ',
QUOTENAME([name]), ' ',
[system_type_name], ';')
, ' ') WITHIN GROUP (ORDER BY [column_ordinal])
FROM sys.dm_exec_describe_first_result_set (#strSQL, NULL, 0)
SET #strUpdateSQL += 'ALTER TABLE #tblResults DROP COLUMN [zz];'
EXEC (#strUpdateSQL);
--*** Now we have #tblResults in the right shape to insert into, and use afterwards
INSERT INTO #tblResults EXEC (#strSQL);
SELECT * FROM #tblResults;
--*** And tidy up
DROP TABLE IF EXISTS #tblResults;