Is it true that SQL Server 2000, you can not insert into a table variable using exec?
I tried this script and got an error message:
EXECUTE cannot be used as a source when inserting into a table variable.
declare #tmp TABLE (code varchar(50), mount money)
DECLARE #q nvarchar(4000)
SET #q = 'SELECT coa_code, amount FROM T_Ledger_detail'
INSERT INTO #tmp (code, mount)
EXEC sp_executesql (#q)
SELECT * from #tmp
If that true, what should I do?
N.B. - this question and answer relate to the 2000 version of SQL Server. In later versions, the restriction on INSERT INTO #table_variable ... EXEC ... were lifted and so it doesn't apply for those later versions.
You'll have to switch to a temp table:
CREATE TABLE #tmp (code varchar(50), mount money)
DECLARE #q nvarchar(4000)
SET #q = 'SELECT coa_code, amount FROM T_Ledger_detail'
INSERT INTO #tmp (code, mount)
EXEC sp_executesql (#q)
SELECT * from #tmp
From the documentation:
A table variable behaves like a local variable. It has a well-defined scope, which is the function, stored procedure, or batch in which it is declared.
Within its scope, a table variable may be used like a regular table. It may be applied anywhere a table or table expression is used in SELECT, INSERT, UPDATE, and DELETE statements. However, table may not be used in the following statements:
INSERT INTO table_variable EXEC stored_procedure
SELECT select_list INTO table_variable statements.
The documentation is misleading.
I have the following code running in production
DECLARE #table TABLE (UserID varchar(100))
DECLARE #sql varchar(1000)
SET #sql = 'spSelUserIDList'
/* Will also work
SET #sql = 'SELECT UserID FROM UserTable'
*/
INSERT INTO #table
EXEC(#sql)
SELECT * FROM #table
DECLARE #q nvarchar(4000)
SET #q = 'DECLARE #tmp TABLE (code VARCHAR(50), mount MONEY)
INSERT INTO #tmp
(
code,
mount
)
SELECT coa_code,
amount
FROM T_Ledger_detail
SELECT *
FROM #tmp'
EXEC sp_executesql #q
If you want in dynamic query
Related
We are using SQL Server 2014 Enterprise with many databases. I have to execute query and get reports / data from every database with EXACT SAME Schema and database starts with Cab
When a new company is added in our ERP project a new database is created with exact schema starting with Cab and incremented number is assigned to it like:
Cab1
Cab2
Cab3
Cab5
Cab10
I can get the database names as:
SELECT name
FROM master.sys.databases
where [name] like 'Cab%' order by [name]
I have to create a Stored Procedure to get data from tables of every database.
How to do that using a Stored Procedure as the databases are created dynamically starting with Cab?
You can use EXEC(#Statement) or EXEC SP_EXECUTESQL if you have to pass parameters.
CREATE OR ALTER PROCEDURE dbo.GetDataFromAllDatabases
AS
BEGIN
DECLARE #T TABLE (id INT NOT NULL IDENTITY(1, 1), dbName VARCHAR(256) NOT NULL)
INSERT INTO #T
SELECT NAME FROM MASTER.SYS.DATABASES WHERE [NAME] LIKE 'Cab%' ORDER BY [NAME]
CREATE TABLE #AllData (......)
DECLARE #Id INT, #DbName VARCHAR(128)
SELECT #Id = MIN(Id) FROM #T
WHILE #Id IS NOT NULL
BEGIN
SELECT #DbName = dbName FROM #T WHERE Id = #Id
DECLARE #Statement NVARCHAR(MAX)
SET #Statement = CONCAT(N'INSERT INTO #AllData (...) SELECT .... FROM ', #DbName, '.dbo.[TableName]')
EXEC(#Statement);
--YOU CAN USE BELOW LINE TOO IF YOU NEED TO PASS VARIABLE
--EXEC SP_EXECUTESQL #Statement, '#Value INT', #Value = 128
SET #Id = (SELECT MIN(Id) FROM #T WHERE Id > #Id)
END
END
A quick and easy dynamic SQL solution would be something like this:
DECLARE #Sql nvarchar(max);
SET #Sql = STUFF((
SELECT ' UNION ALL SELECT [ColumnsList], '''+ [name] + ''' As SourceDb FROM '+ QUOTENAME([name]) + '.[SchemaName].[TableName]' + char(10)
FROM master.sys.databases
WHERE [name] LIKE 'Cab%'
FOR XML PATH('')
), 1, 10, '');
--When dealing with dynamic SQL, print is your best friend...
PRINT #Sql
-- Once the #Sql is printed and you can see it looks OK, you can run it.
--EXEC(#Sql)
Notes:
Use quotename to protect against "funny" chars in identifiers names.
Replace [ColumnsList] with the actual list of columns you need.
There's no need for loops of any kind, just a simple stuff + for xml to mimic string_agg (which was only introduced in 2017).
I've thrown in the source database name as a "bonus", if you don't want it that's fine.
The Order by clause in the query that generates the dynamic SQL is meaningless for the final query, so I've removed it.
I am using MS SQL Server 2017. Suppose I have two stored procedures SPA and SPB. They both take a parameter (e.g. both are integer parameters).
Is there any way to call SPA with a parameter value which would be passed to SPB for execution? Please see example below and it does not work. But this illustrates the idea. I got an error
Must declare the scalar variable "#param1"
I want 100 to be the value for #paramID1 when I run
EXEC SPB #paramID1 = #param1
Please advise. Thanks a million.
CREATE PROCEDURE SPA
#param1 INT
AS
INSERT INTO tbl
SELECT a.*
FROM OPENROWSET('SQLNCLI', 'Server=(local);Trusted_Connection=yes;',
'EXEC SPB #paramID1=#param1') AS a
GO
-- Usage:
EXEC SPA #param1 = 100;
Instead of using dynamic SQL use explicit syntax.
Below is completely working script:
CREATE TABLE dbo.tbl (Name VARCHAR(10))
GO
CREATE PROCEDURE dbo.SPB (#param1 INT)
AS
BEGIN
SELECT #param1
END;
GO
CREATE PROCEDURE dbo.SPA (#param1 INT)
AS
BEGIN
INSERT INTO dbo.tbl (Name)
EXEC dbo.SPB #param1 = #param1
END;
GO
---------------usage---
EXEC dbo.SPA #param1=100;
EXEC dbo.SPA #param1=200;
EXEC dbo.SPA #param1=300;
SELECT * FROM dbo.tbl
GO
DROP TABLE dbo.tbl
DROP PROC dbo.SPA
DROP PROC dbo.SPB
with result:
Name
100
200
300
You could use dynamic sql, like this...
CREATE PROCEDURE SPA #param1 INT
AS
BEGIN
DECLARE #sql nvarchar(max)
SET #sql='INSERT INTO tbl SELECT a.*
FROM OPENROWSET(
''SQLNCLI'',
''Server=(local);Trusted_Connection=yes;'',
''EXEC dbo.SPB #paramID1=' + convert(varchar(10),#param1) + ''')'
Exec(#sql)
END
GO
EXEC SPA #param1 =100;
GO
As I have seen so far, people suggested using dynamic SQL.
For example:
How to pass schema as parameter to a stored procedure in sql server?
How to pass schema name as parameter in stored procedure
However, dynamic SQL has the risk of SQL injection. Hence, I want to know if there are any other safe alternatives?
Basically, this stored procedure that I am creating will be called at runtime. There will be 2 possible schemas to be passed in. And the table name will be passed in as well.
Something like below: (It does not work)
CREATE PROCEDURE [EFM].[usp_readApexTable]
#SCHEMANAME VARCHAR(20) = NULL,
#TABLENAME VARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT *
FROM [#SCHEMANAME].[#TABLENAME];
END
GO
This is just an example of READ action. My plan is to create for CRUD, which requires 4 different stored procedures.
You can use QUOTENAME to avoid any SQL injection and build your dynamic query like the following:
CREATE PROCEDURE [EFM].[usp_readApexTable]
#SCHEMANAME VARCHAR(20) = NULL,
#TABLENAME VARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL VARCHAR(MAX)=N'SELECT * FROM '
+ QUOTENAME(#SCHEMANAME) + '.' + QUOTENAME(#TABLENAME)
EXEC (#SQL)
END
GO
Note: If you have any plan to add parameters also for your WHERE clause, in that case QUOTENAME will not help much, I suggest to to use sp_executesql by passing appropriate parameters used in WHERE clause.
Still you need to use QUOTENAME for schema and table name as SQL excepts it only as literal, you can't use variable names for table and schema.
For example.
declare #sql nvarchar(max)
set #sql = N'select * from ' + quotename(#SCHEMANAME ) + '.' + quotename(#TABLENAME )
+ ' where (City = #City)'
exec sp_executesql
#sql,
N'#City nvarchar(50)',
#City
You can find more details here
You need to use dynamic sql to do this operation
CREATE PROCEDURE [EFM].[usp_readApexTable]
#SCHEMANAME VARCHAR(20) = NULL,
#TABLENAME VARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sqlCommand nvarchar(MAX)
SET #sqlCommand='SELECT * FROM ['+#SCHEMANAME+'].['+#TABLENAME+'];'
--Create Your Temp Table where you can set the records after executing the dynamic query
CREATE TABLE #tmpTbl(
Column1 [datatype]
Column2 [datatype]
.
.
ColumnN
)
INSERT INTO #tmpTbl EXEC sp_executesql #sqlCommand --Copy data to #tmpTbl table
SELECT * FROM #tmpTbl
DROP TABLE #tmpTbl
END
GO
I have a stored procedure where I create a table variable and then try to execute a select against that table variable, but the output throws an incorrect syntax error.
I have my stored procedure (simplified) below :
CREATE PROCEDURE [dbo].[spGetLog]
AS
SET NOCOUNT ON;
Declare #Table table (ID int identity(1,1),
Node varchar(100)
)
insert into #Table(Node) values ('employee')
Declare #sqlquery AS NVARCHAR(1000)
SET #sqlquery = 'select * from #Table;'
EXEC (#sqlquery)
Gives an error --
Incorrect syntax near '#Table'
In reality the #sqlquery variable I have is complex and I need to use a variable and
execute the query.
Is there a way I can still execute my stored procedure using a variable? Any other
suggestions are welcome.
As David W mentioned in his comment, just use a temp table (not a table variable) if you want something that is visible within your EXEC scope:
CREATE TABLE #Table (ID int identity(1,1),
Node varchar(100)
)
insert into #Table(Node) values ('employee')
Declare #sqlquery AS NVARCHAR(1000)
SET #sqlquery = 'select * from #Table;'
EXEC (#sqlquery)
DROP TABLE #Table;
Is this incorrect, can't we pass the table name to a select query dynamically?
This is giving me a error 'Must declare the table variable #TblName'
DECLARE #TblName VARCHAR(30)
SET #TblName = 'User'
SELECT *
FROM #TblName
You need to create a dynamic SQL query, preferably using the QUOTENAME function. You can avoid any issues from malicious input by using QUOTENAME function.
Here is a sample script that illustrates how to query a table by creating a dynamic SQL query by passing in a table name. You can change the table name by value to the variable #tablename.
Create and insert script for sample:
CREATE TABLE sample
(
id INT NOT NULL
);
INSERT INTO sample (id) VALUES
(1),
(2),
(3),
(4),
(5),
(6);
Dynamic SQL script:
DECLARE #execquery AS NVARCHAR(MAX)
DECLARE #tablename AS NVARCHAR(128)
SET #tablename = 'sample'
SET #execquery = N'SELECT * FROM ' + QUOTENAME(#tablename)
EXECUTE sp_executesql #execquery
Demo:
Click here to view the demo in SQL Fiddle.
Suggested read:
The Curse and Blessings of Dynamic SQL
you have to use dynamic sql execution
wrap your statement in #selectstr
use exec sp_executesql #selectstr
You can do this thing by using dynamic query, Check below
DECLARE #TblName VARCHAR(30)
DECLARE #vQuery NVARCHAR(100)
SET #TblName = 'User'
SET #vQuery = 'SELECT * FROM ' + #TblName
EXECUTE sp_executesql #vQuery