Using string/array to buid query - sql

I want to create a procedure which selects items from database where id is not in specified collection.
The collection is passed as text parameter (here it is declared to show the problem):
DECLARE #IDs nvarchar(500);
SET #IDS = '2499043,2499042,2499041,2499040,2499039,2499038,2499037'
I found the solution that works and displays result:
Declare #ProductsSQL nvarchar(max);
Select #ProductsSQL = 'SELECT * FROM [Items] WHERE (ID not in (' + #IDs + '))'
exec sp_executesql #ProductsSQL
The problem is that would like to process (make next select from this result) and return them.
How can I get results from 'sp_executesql'?
Or can anyone suggest other solution - the form of parameter can change (string was the best in my opinion but as you can see I cannot solve the problem)

You can store result of the Query into temptable and use that 'temptable' for processing.
You can try this code :
Declare #ProductsSQL nvarchar(max);
Select #ProductsSQL = 'SELECT * into [tempdb].[dbo].[temptable] FROM [Items] WHERE (ID not in (' + #IDs + '))'
exec sp_executesql #ProductsSQL
SELECT * FROM [tempdb].[dbo].[temptable]
DROP TABLE [tempdb].[dbo].[temptable]

Related

Insert data into a table from Open Query with variable

I am trying to using OPENQUERY to pull some data into a table. Here's what my code looks like:
DECLARE #TSQL VARCHAR(MAX)
DECLARE #CD VARCHAR(10) = 'XX'
DECLARE #OracleData TABLE (Cd VARCHAR(20), ApptDATE Datetime )
INSERT INTO #OracleData(Cd,ApptDATE )
SELECT #TSQL = 'SELECT * FROM OPENQUERY(LinkedServer,''Select p.Cd, p.AppDate
from ta.table1 p
where p.IdCode = ''''' + #CD + ''''''')'
EXEC (#TSQL)
I end up with the following error:
An INSERT statement cannot contain a SELECT statement that assigns
values to a variable.
When I attempt to run the EXEC(#TSQL) without the INSERT it works like a charm, but I am unable to do an insert.
Any ideas how I can possibly resolve this?
Thanks.
You are doing this the wrong way round.
Don't insert the #TSQL variable into your table, set the variable, then insert the results using INSERT...EXEC...
DECLARE #TSQL nvarchar(max) = '
SELECT *
FROM OPENQUERY(LinkedServer,
''Select p.Cd, p.AppDate
from ta.table1 p
where p.IdCode = ''''' + #CD + ''''''')
';
INSERT INTO #OracleData (Cd, ApptDATE)
EXEC (#TSQL);
I'm sure there is an excellent reason you are not just using a straight Linked Server query without dynamic SQL, but I can't think of one.

How to use a dynamic WHERE clause in my SQL CTE query?

I've a question about my SQL CTE construction. I'm working with Azure Data Factory and a Stored Procedure in my database. What I want to do is:
Return my data from my view to Azure Data Factory in JSON format.
Return the data filtered dynamically in the WHERE clause based on my ObjectCode in my view in JSON format.
-> To test step 2 I tried with a statical declared ObjectCode
But the single quote does not work right in the WHERE clause. I tried some things with REPLACE, CHAR(39) and double the quotes. Like they said here, here and here
Step 1 I've finished succesfull with this code:
BEGIN
DECLARE #TABLE TABLE(RESULT NVARCHAR(MAX))
DECLARE #QUERY NVARCHAR(MAX) = '
;WITH x(Params) as
(
SELECT * FROM [Schema].[View] FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
Select * from x
'
Insert #TABLE
EXEC (#QUERY)
Select ',"pipelineParameters": ' + LEFT(RESULT,LEN(RESULT)-1) + '}' as Params from #TABLE;
END
This query above gave me the right result. But, now I need to make a change for Step 2. I need to filter with the WHERE clause in the query.
So, I tried:
DECLARE #TABLE TABLE(RESULT NVARCHAR(MAX))
DECLARE #ObjectCode NVARCHAR(MAX) = 'Objectname'
DECLARE #QUERY NVARCHAR(MAX) = '
;WITH x(Params) as
(
SELECT * FROM [Schema].[View]
WHERE Objectcode = REPLACE(#ObjectCode, '''', '')
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
Select * from x
'
Insert #TABLE
EXEC (#QUERY)
Select ',"pipelineParameters": ' + LEFT(RESULT,LEN(RESULT)-1) + '}' as Params from #TABLE;
But when I run these query I get this error:
Does anyone know what I can improve here so I can get it working?
Does this do what you want?
Insert #TABLE
exec sp_executesql #QUERY, N'#ObjectCode nvarchar(max)', #ObjectCode=#ObjectCode;
As written, I would expect a syntax error when the query is run because of this WHERE clause:
WHERE Objectcode = REPLACE(#ObjectCode, '', ')
I think you intend:
DECLARE #QUERY NVARCHAR(MAX) = '
WITH x(Params) as (
SELECT *
FROM [Schema].[View]
WHERE Objectcode = REPLACE(#ObjectCode, '''''''', '''')
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
Select *
from x';
Quoting things in dynamic SQL is always verbose. You can print out #Query to see if it is really what you intend.
'
Thanks Gordon, the first one works for me:
Insert #TABLE
exec sp_executesql #QUERY, N'#ObjectCode nvarchar(max)', #ObjectCode=#ObjectCode;

SELECT INTO dynamic temp table using procedure with dynamic parameter

I can't find a full solution to my problem. I have an existing stored procedure that takes dynamic input as a parameter value. I need to execute this procedure (with a dynamic variable) and would like to somehow SELECT * INTO #mytable without having to declare the schema of the temp table.
I've tried using OPENROWSET but it doesn't allow me to specify the variable (only hard-code it):
select * into #table from openrowset('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;', 'exec SERVER..MYSTOREDPROCEDURE #parameter = 123')
The only other way I'm aware of is wrapping it in a string and using EXEC(#sql), but I can't figure out how to "SELECT * INTO #table" from that.
What are my options? Can I create a UDF table function that can return a dynamic table? Doubtful...
I'm guessing here, but you'll need to do the whole thing in dynamic SQL. So, instead, something like:
DECLARE #SQL nvarchar(MAX);
DECLARE #param nvarchar(10) = 123;
SET #SQL = N'SELECT *' + NCHAR(10) +
N'INTO #table' + NCHAR(10) +
N'FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'', ''exec SERVER..MYSTOREDPROCEDURE #parameter = ' + QUOTENAME(#param,N'''') +N''');' + NCHAR(10) +
N'SELECT *' + NCHAR(10) + --Of course, I assume you're doing something more complex that a SELECT *.
N'FROM #table;';
PRINT #SQL;
EXEC sp_executesql #SQL;
I think I figured it out. I really only had to modify the temp variable names to put the temp table into the global scope. This works for me with my actual tables (I renamed them for the purposes of this post).
IF OBJECT_ID ('tempdb..##mytemptable') is not null drop table ##mytemptable
declare #id int = 112
declare #sql nvarchar(max) ='SELECT * INTO ##mytemptable FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'', ''exec SERVER..MyStoredProcedure #ID =' + convert(varchar(10), id) + ''')'
-- invokes and inserts into ##mytemptable
exec sp_executesql #sql
-- now I can query from the global scope
select * from ##mytemptable

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

Stored Procedure That Return Different Table According To Parameter

I want to write a stored procedure that takes #FirmId as a parameter and I will use the related table according to this parameter.
What I want to obtain (but I don't want to use) is something like that:
CREATE PROCEDURE spFirmDetailGetByFirmId
#FirmId AS INT
AS
BEGIN
IF #FirmId = 1
SELECT * FROM Firm1
ELSE IF #FirmId = 2
SELECT * FROM Firm2
.
.
.
.
ELSE IF #FirmId = 1000
SELECT * FROM Firm1000
END
And also I don't want to create query string and then EXEC it, something like that in the fallowing code block. Because the real query is too complex and it will be very hard to manage if I use this option.
CREATE PROCEDURE spFirmDetailGetByFirmId
#FirmId AS INT
AS
BEGIN
DECLARE #Query AS NVARCHAR(MAX) = 'SELECT * FROM Firm'
SET #Query = #Query + CAST(#FirmId AS NVARCHAR(10))
EXEC(#Query)
END
Is there any other option?
Thanks.
I take your Yes the tables are identical and will be kept identical to suggest two approaches:
DECLARE #Firm VARCHAR(10)='Firm3';
SELECT * FROM Firm1 WHERE #Firm='Firm1'
UNION ALL
SELECT * FROM Firm2 WHERE #Firm='Firm2'
UNION ALL
SELECT * FROM Firm3 WHERE #Firm='Firm3'
[...]
UNION ALL
SELECT * FROM Firm1000 WHERE #Firm='Firm1000'
The second is:
DECLARE #query NVARCHAR(MAX)='SELECT * FROM ####';
SET #query=REPLACE(#query,'####',#Firm);
EXEC (#query)
The second could be used with a VIEW (in place of the #query), where you could read the VIEW's definition into the variable and create an ALTER VIEW-statement dynamically... Your procedure would call the same VIEW (but this would crash with parallel calls!)
This code can by use in a stored procedure to automatic create the view, every time you need to add columns
declare #tableId int
declare #columns varchar(max)
declare #tablesCount int
declare #tableName varchar(255)
declare #query varchar(255)
declare #id int
declare #result nvarchar(max)
set #columns = ''
set #tableName = 'Firm'
set #id = 1
set #result = ''
--Base table
select #tableId = object_id from sys.tables where name =#tableName
--Count how many table with the 'same name'
select #tablesCount= count(*) from sys.tables where name like #tableName+'%'
--Build Columns to add in the view
select #columns =#columns+name+', 'from Sys.columns where object_id = #tableId
--Drop View
set #result = 'Drop view vw_'+#tableName
exec sp_executesql #result
set #result=''
while(#id<=#tablesCount)
Begin
declare #idVarchar varchar(10)
set #idVarchar = cast(#id as varchar(10))
set #result =#result+'Select '+#columns+#idVarchar+' as FirmId from '+#tableName+#idVarchar
+'
Union all
'
set #id =#id+1
End
set #result = substring(#result, 1, len(#result)-12)
set #result='Create view vw_'+#tableName+' as
'+#result
exec sp_executesql #result
There is a another choice to this, you can also use sp_helpText to get the current definition of the view and append only add new table identifier