How to execute a SQL String that references a table variable? - sql

I have a table variable in SQL Server 2008
DECLARE #specsAndModel TABLE
(
specName VARCHAR(50)
,specVal VARCHAR(50)
)
INSERT INTO #specsAndModel
VALUES('[modelNumber]', 'F00-B4R')
Then, I later build a string called #query, which I ultimately try to pass into EXECUTE, as in the following example:
DECLARE #query NVARCHAR(MAX);
SET #query = 'SELECT specName, specVal FROM #specsAndModel'
EXECUTE(#query)
However, SQL Server gives me the error message: Must declare the table variable "#specsAndModel".
After searching around, I think this might be related to the execution context, but I haven't been able to resolve the problem.
Is it even possible for me to use a table variable in a call to the execute function?

The table you are creating is a table variable which is not available outside of its initial scope. There are a few ways to fix this:
Create a Global Temp Table (Disclaimer: this can cause problems if more that one user attempts to run this at the same time.):
create table ##specsAndModel
(
specName VARCHAR(50)
,specVal VARCHAR(50)
)
INSERT INTO ##specsAndModel
VALUES('[modelNumber]', 'F00-B4R')
DECLARE #query NVARCHAR(MAX);
SET #query = 'SELECT specName, specVal FROM ##specsAndModel'
EXECUTE(#query)
Create a Local Temp Table instead of global:
create table #specsAndModel
(
specName VARCHAR(50)
,specVal VARCHAR(50)
)
INSERT INTO #specsAndModel
VALUES('[modelNumber]', 'F00-B4R')
DECLARE #query NVARCHAR(MAX);
SET #query = 'SELECT specName, specVal FROM #specsAndModel'
EXECUTE(#query)
Execute the create table inside of your dynamic SQL (ugly):
DECLARE #query NVARCHAR(MAX);
SET #query = 'DECLARE #specsAndModel TABLE
(
specName VARCHAR(50)
,specVal VARCHAR(50)
)
INSERT INTO #specsAndModel
VALUES(''[modelNumber]'', ''F00-B4R'')
SELECT specName, specVal FROM #specsAndModel'
exec(#query)
Instead of using a temp table, create an actual table and then drop it when done (Disclaimer: this can cause problems if more that one user attempts to run this at the same time.):
create TABLE specsAndModel
(
specName VARCHAR(50)
,specVal VARCHAR(50)
)
INSERT INTO specsAndModel
VALUES('[modelNumber]', 'F00-B4R')
DECLARE #query NVARCHAR(MAX);
SET #query = 'SELECT specName, specVal FROM specsAndModel'
EXECUTE(#query)
drop table specsAndModel
Here is an link to a discussion about temp tables and table variables:
Should I use a #temp table or a #table variable?
Edit: You can pass in a table variable using sp_executesql:
create type specsAndModel as table (
specName VARCHAR(50)
,specVal VARCHAR(50)
)
go
declare #t specsAndModel
insert #t VALUES('[modelNumber]', 'F00-B4R')
exec sp_executesql N'select specName, specVal from #var', N'#var specsAndModel readonly', #t
Using either the global ##temp tables and a permanent table run risks in that if more than one users attempts to run the process, there could be conflicts.
You are safer using either a local #temp table or passing the table variable using sp_executesql.

You also have to create your table variable inside the in the string.
DECLARE #query NVARCHAR(MAX);
SET #query = 'DECLARE #specsAndModel TABLE ( specName VARCHAR(50) ,specVal VARCHAR(50))'
SET #Query = #Query + ' INSERT INTO #specsAndModel VALUES(''modelNumber'',''abcd''); SELECT specName, specVal FROM #specsAndModel'
EXEC (#query)

Related

Declare local table <column_definition> from variable

I need to create Dynamic columns for local table. This is my example code
Declare #ColumnsTable AS varchar(max) = '"column_a" varchar(100),"column_b" varchar(100), "column_c" varchar(100)'
Declare #Table AS Table (#ColumnsTable)
Select * from #Table
I can't use EXEC

not able to use sp_executesql command

I need to execute below query
SELECT *, IDENTITY( int ) AS IDColumn INTO #SmootheningTable FROM #TableName
where #SmootheningTable is temporary table
and #TableName is name of table
I need to use command either EXEC or sp_executesql to execute.
If I use EXEC, I wont be able to use #SmootheningTable in later portion of my stored procedure.
And while trying sp_executesql, I am getting error stating #statement error.
How can I use sp_executesql for above given query.
Or is there any other way to execute?
this is the query I am using
DECLARE #TablePlaceHolder VARCHAR(50)='';
DECLARE #SmootheningQuery NVARCHAR(max) = 'SELECT *, IDENTITY( int ) AS IDColumn INTO #SmootheningTable FROM #TablePlaceHolder';
EXEC sp_executesql #SmootheningQuery, N'#TablePlaceHolder varchar(50)', #PlanDetailTempTableName
and i am getting below error
Must declare the table variable "#TablePlaceHolder".
Thanks in advance
There are two issues in your code:-
First : Putting the variable name inside the string, put in out like next:-
instead of this line:-
DECLARE #SmootheningQuery NVARCHAR(max) = 'SELECT *, IDENTITY( int ) AS
IDColumn INTO #SmootheningTable FROM #TablePlaceHolder';
Type this line:-
DECLARE #SmootheningQuery NVARCHAR(max) = 'SELECT *, IDENTITY( int ) AS
IDColumn INTO #SmootheningTable FROM ' + #TablePlaceHolder;
Second: Don't use local temp table within sp_executeSql,
The Local temporary table [with one hash # ] is visible in current session only, use global temporary tables instead [with two hashes ## ] are visible in all sessions,
So instead of
#SmootheningTable
Type
##SmootheningTable
Demo (All Code): -
Create table MyTable (id int , name nvarchar(100))
go
insert into MyTable values (1, 'Ahmed');
insert into MyTable values (2, 'Abdelqader');
go
declare
#TableName varchar(50),
#MyQuery nvarchar(200)
set #TableName = 'MyTable'
set #MyQuery = 'select * Into ##MYTempTable From ' + #TableName
exec sp_executesql #MyQuery
select * from ##MYTempTable
Result:-
id name
1 Ahmed
2 Abdelqader
Please Try This,
CREATE PROC usp_SmootheningTable
AS
BEGIN
SELECT *, IDENTITY( int ) AS IDColumn INTO #SmootheningTable FROM
TableName
SELECT * FROM #SmootheningTable
END
GO
Please try this out
CREATE TABLE #Temp
(
Columns
)
DECLARE #SQL NVARCHAR(MAX)
DECLARE #TableName VARCHAR(MAX)
SET #TableName = 'TableName'
SET #SQL = 'SELECT TOP 10 * FROM '+#TableName
INSERT INTO #Temp
EXEC SP_EXECUTESQL #SQL
SELECT * FROM #Temp

How to run string math expression in SQL Server (trigger or function)

I want to run:
select Mycalculatefunction('((3*4)-3)*5')
select ('((3*4)-3)*5')
OUTPUT: ((3*4)-3)*5 wrong (not int value)
My desired output is: 45
I defined a stored procedure:
create PROCEDURE dbo.Eval
(#exp varchar(MAX))
AS
SET NOCOUNT ON
DECLARE #SQLString NVARCHAR(MAX)
SET #SQLString = 'SELECT '+#exp
EXEC sp_executesql #SQLString
I call it:
exec dbo.Eval '((3*4)-3)*5'
How can I do in this process is the trigger?
Your SP is vulnerable to injection. F.e. I pass exec dbo.Eval '1;DROP TABLE some_table;'. Better use xml.query:
CREATE PROCEDURE dbo.Eval
#formula nvarchar(max)
AS
DECLARE #sql nvarchar(max)
SELECT #sql = N'
DECLARE #x xml = ''''
SELECT CAST(#x.query('''+#formula+''') as nvarchar(max))'
EXEC sp_executesql #sql
Then
EXEC dbo.Eval '((3*4)-3)*5'
Output:
45
Triggers part (as there were no info about your tables, just general explanation, I add full batch with comments):
--Create table that will store Formulas
CREATE TABLE Formulas (
ID int IDENTITY(1,1) NOT NULL,
Formula nvarchar(max) NULL,
CONSTRAINT PK_ID PRIMARY KEY (ID)
)
GO
--Create table to store results of the formulas
CREATE TABLE Results (
T1_ID int NOT NULL,
Result int NULL
)
GO
--Linked by ID
ALTER TABLE Results ADD CONSTRAINT FK_Formulas_Results FOREIGN KEY (T1_ID)
REFERENCES Formulas (ID)
GO
--Create a Table Valued Parameter
CREATE TYPE FormulaResults AS TABLE (
ID int NOT NULL,
Formula nvarchar(max) NULL
)
GO
--Create a procedure to do the count
CREATE PROCEDURE dbo.GetResults
#TVP FormulaResults READONLY
AS
DECLARE #sql nvarchar(max)
SELECT #sql = N'DECLARE #x xml = '''' '
SELECT #sql = #sql + 'SELECT '+CAST(ID as nvarchar(max))+' as ID, CAST(#x.query('''+Formula+''') as nvarchar(max)) UNION ALL '
FROM #TVP
SELECT #sql = LEFT(#sql,LEN(#sql)-LEN('UNION ALL '))
EXEC sp_executesql #sql
GO
--Create a trigger that will count formula after insert and update
CREATE TRIGGER GetResultsTrigger
ON Formulas
AFTER INSERT, UPDATE
AS
DECLARE #FormulaTVP AS FormulaResults
DECLARE #Results TABLE(
T1_ID int NOT NULL,
Result int NULL
)
INSERT INTO #FormulaTVP
SELECT *
FROM inserted
INSERT INTO #Results
EXEC dbo.GetResults #FormulaTVP
MERGE Results r
USING #Results s
ON r.T1_ID = s.T1_ID
WHEN NOT MATCHED THEN
INSERT VALUES (s.T1_ID, s.Result)
WHEN MATCHED THEN
UPDATE SET Result = s.Result;
After that run:
INSERT INTO [Formulas] VALUES
('1+3'),('2+2*8')
SELECT [ID],
[Formula]
FROM [Test].[dbo].[Formulas]
SELECT [T1_ID],
[Result]
FROM [Test].[dbo].[Results]
Output:
ID Formula
1 1+3
2 2+2*8
T1_ID Result
1 4
2 18
image 1
ALTER FUNCTION [dbo].[Calculate]
( #expression AS VARCHAR(MAX)
)
RETURNS xml
AS
BEGIN
-- routine body goes here, e.g.
-- SELECT 'Navicat for SQL Server'
DECLARE #result xml
declare #x xml=''
--I can not pass as a parameter
select #result=#x.query(('(4*3)*5-10'))
return #result;
END
i call this function:
SELECT CAST(CAST(CAST(dbo.[Calculate]('How do I pass parameters') AS XML) AS VARCHAR(100)) AS DECIMAL(4,2))
Output:
50.00
select #result=#x.query('sql:variable("#expression")')
result: '2+2' :(((

How to use Table Variable in Dynamic Query

I want to use Table Variable instead of Temp Table but My main query construction is Dynamic .
Dynamic query is in single quote so how can I fetch data from #TableVariable.
I dont want to remove dynamic query because some of parameter will added later.
e.g. following is error code , where I have wrote table variable into Dynamic Query........
/*Declare Table Variable*/
DECLARE #TempVehicles TABLE
(
[VehicleID] INT
)
/*Insert data into Table Variable*/
INSERT INTO #TempVehicles
(
[VehicleID]
)
SELECT VehicleID
FROM tbl_Vehicles
/*Dynamic Query and Main SQL Construction*/
DECLARE #SQL NVARCHAR(MAX)
SET #SQL ='SELECT Cust_ID,A.VehicleID,GISInfo
FROM #TempVehicles A INNER JOIN tbl_GISData B ON A.VehicleID=B.VehicleID'
EXECUTE SP_EXECUTESQL #SQL
Help me , in this .
Thanks in Advance.
Try This :
CREATE TYPE IntegerTableType AS TABLE (ID INT);
go
DECLARE #TempVehicles IntegerTableType;
INSERT #TempVehicles
values (1);
DECLARE #SQL NVARCHAR(MAX);
SET #SQL ='SELECT *
FROM #TempVehicles;';
EXECUTE SP_EXECUTESQL #SQL,N'#TempVehicles IntegerTableType READONLY',
#TempVehicles;
As an alternate solution you can use #TempVehicles instead of storing it in variable.
SELECT VehicleID
into #TempVehicles
FROM tbl_Vehicles
/*Dynamic Query and Main SQL Construction*/
DECLARE #SQL NVARCHAR(MAX)
SET #SQL ='SELECT Cust_ID,A.VehicleID, GISInfo
FROM #TempVehicles A INNER JOIN tbl_GISData B ON A.VehicleID=B.VehicleID;
Drop Table #TempVehicles'
EXECUTE SP_EXECUTESQL #SQL
Try and check whether it meets your requirement.

Pass a TABLE variable to sp_executesql

I'm trying to pass a TABLE variable to the sp_executesql procedure:
DECLARE #params NVARCHAR(MAX)
SET #params = '#workingData TABLE ( col1 VARCHAR(20),
col2 VARCHAR(50) )'
EXEC sp_executesql #sql, #params, #workingData
I get the error:
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'TABLE'.
I tried omitting the column specification after 'TABLE'. I also tried to declare the table as a variable inside the dynamic SQL. But no luck...
Seems to me that TABLE variables aren't allowed to be passed as parameters in this procedure?. BTW: I'm running MSSQL2008 R2.
I'm not interested in using a local temp table like #workingData because I load the working data from another procedure:
INSERT INTO #workingData
EXEC myProc #param1, #param2
Which I cannot do directly into a temp varaible (right?)...
Any help appreciated!
If you are using SQL Server 2008, to pass a table variable to a stored procedure you must first define the table type, e.g.:
CREATE TYPE SalesHistoryTableType AS TABLE
(
[Product] [varchar](10) NULL,
[SaleDate] [datetime] NULL,
[SalePrice] [money] NULL
)
GO
or use an existing table type stored in the database.
Use this query to locate existing table types
SELECT * FROM sys.table_types
To use in an stored procedure, declare an input variable to be the table:
CREATE PROCEDURE usp_myproc
(
#TableVariable SalesHistoryTableType READONLY
)
AS BEGIN
--Do stuff
END
GO
Populate the table variable before passing to the stored procedure:
DECLARE #DataTable AS SalesHistoryTableType
INSERT INTO #DataTable
SELECT * FROM (Some data)
Call the stored procedure:
EXECUTE usp_myproc
#TableVariable = #DataTable
Further discussions here.
OK, this will get me what I want, but surely isn't pretty:
DECLARE #workingData TABLE ( col1 VARCHAR(20),
col2 VARCHAR(20) )
INSERT INTO #workingData
EXEC myProc
/* Unfortunately table variables are outside scope
for the dynamic SQL later run. We copy the
table to a temp table.
The table variable is needed to extract data directly
from the strored procedure call above...
*/
SELECT *
INTO #workingData
FROM #workingData
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT * FROM #workingData'
EXEC sp_executesql #sql
There must be a better way to pass this temporary resultset into sp_executesql!?
Regards
Alex
While this may not directly answer your question, it should solve your issue overall.
You can indeed capture the results of a Stored Procedure execution into a temporary table:
INSERT INTO #workingData
EXEC myProc
So change your code to look like the following:
CREATE TABLE #workingData ( col1 VARCHAR(20),
col2 VARCHAR(20) )
INSERT INTO #workingData
EXEC myProc
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT * FROM #workingData'
EXEC sp_executesql #sql
Regards,
Tim
Alter PROCEDURE sp_table_getcount
#tblname nvarchar(50) ,
#totalrow int output
AS
BEGIN
Declare #params nvarchar(1000)
Declare #sql nvarchar(1000)
set #sql = N'Select #cnt= count(*) From #tbl'
set #params = N'#tbl nvarchar(50) , #cnt int OUTPUT'
Exec sp_executesql #sql , #params ,#tbl=#tblname , #cnt = #totalrow OUTPUT
END
GO
Please note that the above code will not work as table as a object is out of the scope.It will give you the error: must declare table variable.In order to work around we can do the following.
Alter PROCEDURE sp_table_getcount
#tblname nvarchar(50) ,
#totalrow int output
AS
BEGIN
Declare #params nvarchar(1000)
Declare #sql nvarchar(1000)
set #sql = N'Select #cnt= count(*) From dbo.' + #tblname
set #params = N'#cnt int OUTPUT'
Exec sp_executesql #sql , #params , #cnt = #totalrow OUTPUT
END
GO
So-called TableType is tricky. #Alex version should work. However, to simplify and faster performance, go check sys.tables for matching table name while not compromise security and performance.
Here it is
create proc [dbo].Test11
#t1 AS nvarchar(250), #t2 nvarchar(250)
AS
BEGIN
SET nocount ON;
DECLARE #query AS nvarchar(MAX)
if exists (select * from sys.tables where name = #t1) and
exists (select * from sys.tables where name = #t2)
begin
SET #query = N'select * FROM '+ #t1 + N' join ' + #t2 + N' ON ...' ;
select 'Safe and fast'
print #query
exec sp_executesql #query
end
else
select 'Bad, no way Jose.'
SET nocount OFF;
END
GO