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

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;

Related

Using string/array to buid query

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]

Building insert statement with quotes in SQL

I am trying to understand how the single quotes work in SQL.
All I want to achieve is
INSERT INTO LOGTABLE
(ID,
ROLLNO)
VALUES ('E8645F55-A18C-43EA-9D68-1F9068F8A9FB',
28)
Here ID is a uniqueidentifier field and rollNo is an int.
So I have this sample test code:
set #query = '
insert into fileLog
(
id,
rollNo
)
values
('+
'''' + NEWID() + '''' + ',' + 28 +
')'
print #query
I have tried several combination of single quotes left and right but nothing works. I would really appreciate if someone could solve this. But in particular I wanted to know how many single quotes are required on both sides of a string to get something like 'SQL'.
Thanks
My question is: Why are you using dynamic SQL? It's one of those techniques that is useful in some situations, but can be abused easily.
As for the answer to your question, I use a technique to help minimize the flipping in and out of SQL construction:
DECLARE #query VARCHAR(MAX)
SET #query = '
insert into fileLog
(
id,
rollNo
)
values
(''|NEWID|'', |INT|)'
SET #query = REPLACE(#query, '|NEWID|', NEWID())
SET #query = REPLACE(#query, '|INT|', 28)
PRINT #query
(I'm going to assume you need dynamic SQL for reasons not obvious in the question, since this doesn't seem to require dynamic SQL at all.)
As #Gidil suggested, the problem here is trying to treat a uniqueidentifier as a string. In this case, there really isn't any reason to declare NEWID() in the outer scope, since you can simply say:
SET #query = 'INSERT ... VALUES(NEWID(), 28);';
PRINT #query;
Now, you should be using NVARCHAR(MAX) as your parameter, because ultimately you should be executing this using sp_executesql, not EXEC().
If you need to have a literal you can double up the quotes:
DECLARE #string VARCHAR(32);
SET #string = 'foo';
SET #query = N'INSERT ... VALUES(''' + #string + ''', 28);';
However I find it more readable to use CHAR(39):
SET #query = N'INSERT ... VALUES(' + CHAR(39) + #string + CHAR(39) + ', 28);';
And even better is to not append these variables to a string anyway. You should be using properly typed parameters where possible.
DECLARE #query NVARCHAR(MAX);
DECLARE #string VARCHAR(32), #newid UNIQUEIDENTIFIER, #id INT;
SELECT #string = 'foo', #newid = NEWID(), #id = 28;
SET #query = N'INSERT ... VALUES(#string, #newid, #id);';
EXEC sp_executesql #query,
N'#string VARCHAR(32), #newid UNIQUEIDENTIFIER, #id INT',
#string, #newid, #id;
It's bulkier, sure, but it's much safer from SQL injection and it lets you stop trying to figure out and deal with the hassle of embedding single quotes into the string...
Try this:
DECLARE #query VARCHAR(MAX)
SET #query = ' insert into fileLog ( id, rollNo ) values (' + '''' + Cast(Newid() AS VARCHAR(100)) + ''''
+ ',28)'
PRINT #query
The problem isn't the quotes, but the data types.
NEWID isn't a string and neither is the number 28.
Good luck!
Unless you need dynamic SQL for some reason, you can probably just do this:
insert into fileLog
(
id,
rollNo
)
values
(
NEWID(),
28
)

how do I select records that are like some string for any column in a table?

I know that I can search for a term in one column in a table in t-sql by using like %termToFind%. And I know I can get all columns in a table with this:
SELECT *
FROM MyDataBaseName.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'MyTableName`
How can I perform a like comprparison on each of the columns of a table? I have a very large table so I can't just spell out LIKE for each column.
As always, I'll suggest xml for this (I'd suggest JSON if SQL Server had native support for it :) ). You can try to use this query, though it could perform not so well on large number of rows:
;with cte as (
select
*,
(select t.* for xml raw('data'), type) as data
from test as t
)
select *
from cte
where data.exist('data/#*[local-name() != "id" and contains(., sql:variable("#search"))]') = 1
see sql fiddle demo for more detailed example.
Important note by Alexander Fedorenko in comments: it should be understood that contains function is case-sensitive and uses xQuery default Unicode code point collation for the string comparison.
More general way would be to use dynamic SQL solution:
declare #search nvarchar(max)
declare #stmt nvarchar(max)
select #stmt = isnull(#stmt + ' or ', '') + quotename(name) + ' like #search'
from sys.columns as c
where c.[object_id] = object_id('dbo.test')
--
-- also possible
--
-- select #stmt = isnull(#stmt + ' or ', '') + quotename(column_name) + ' like #search'
-- from INFORMATION_SCHEMA.COLUMNS
-- where TABLE_NAME = 'test'
select #stmt = 'select * from test where ' + #stmt
exec sp_executesql
#stmt = #stmt,
#params = N'#search nvarchar(max)',
#search = #search
sql fiddle demo
I'd use dynamic SQL here.
Full credit - this answer was initially posted by another user, and deleted. I think it's a good answer so I'm re-adding it.
DECLARE #sql NVARCHAR(MAX);
DECLARE #table NVARCHAR(50);
DECLARE #term NVARCHAR(50);
SET #term = '%term to find%';
SET #table = 'TableName';
SET #sql = 'SELECT * FROM ' + #table + ' WHERE '
SELECT #sql = #sql + COALESCE('CAST('+ column_name
+ ' as NVARCHAR(MAX)) like N''' + #term + ''' OR ', '')
FROM INFORMATION_SCHEMA.COLUMNS WHERE [TABLE_NAME] = #table
SET #sql = #sql + ' 1 = 0'
SELECT #sql
EXEC sp_executesql #sql
The XML answer is cleaner (I prefer dynamic SQL only when necessary) but the benefit of this is that it will utilize any index you have on your table, and there is no overhead in constructing the XML CTE for querying.
In case someone is looking for PostgreSQL solution:
SELECT * FROM table_name WHERE position('your_value' IN (table_name.*)::text)>0
will select all records that have 'your_value' in any column. Didn't try this with any other database.
Unfortunately this works as combining all columns to a text string and then searches for a value in that string, so I don't know a way to make it match "whole cell" only. It will always match if any part of any cell matches 'your_value'.

Error with Dynamic SQL statement cutting off with exec command

I am attempting to pivot a column with 400 or so unique values with the following code:
Declare #t VARCHAR(10)
Declare #A VARCHAR(1000)
Declare #B VARCHAR(1000)
set #A='SELECT Name, IRIS_ID__c'
SET #B='('
SELECT #A=#A+',['+Question_Concept_With_ImpactArea__c+'] as ['+Question_Concept_With_ImpactArea__c+']',#B=#B+'['+Question_Concept_With_ImpactArea__c+']'
FROM (SELECT DISTINCT Question_Concept_With_ImpactArea__c
FROM Company_Number_Response) cur
-- removing last ',' from both variables
SET #B=SUBSTRING(#B,1,LEN(#B)-1)
SET #A=#A+ + '
FROM
(SELECT NAME, IRIS_ID__c, Selected, Question_Concept_With_ImpactArea__c
FROM Company_Number_Response) s PIVOT (max(Unified_Response__c)
FOR Question_Concept_With_ImpactArea__c IN ' +#B+')) p ORDER BY [IRIS_ID__c];'
exec(#A);
Running this code throws an error that "Unclosed quotation mark after the character string 'CM_PcCOGSSup'
Incorrect Syntax near 'CM_PcCOGSSup'
When I change the last command from exec to print I can see that many of the values are being read, but the statement simply cuts off at the value in the above error. I checked the data and do not see any characters that would be causing this. Additionally, I thought the result might be too long and changed the max number for results to text to 8192.
Any help would be greatly appreciated.
Assuming you're using SQL Server 2005 or up, change your variable declarations to varchar(max). It's cutting off because you've only supplied varchar(1000), and string concatenation does not automatically lengthen char data types--they get truncated.
In SQL 2000 you can only use varchar(8000). If you need longer than that you will have to get creative--a pretty difficult task.
You also have SET #A=#A+ + '. If that's working, it's a surprise to me, but in any case there should only be one + there.
And, you should not just put square brackets around columns to make them a valid sysname data type. You should use the QuoteName function:
SELECT #A = #A + ',' + QuoteName(Question_Concept_With_ImpactArea__c) ...
Try this one -
DECLARE #Columns VARCHAR(MAX)
DECLARE #SQL NVARCHAR(MAX)
SELECT #Columns = STUFF((
SELECT DISTINCT ', ['+ Question_Concept_With_ImpactArea__c + ']'
FROM dbo.Company_Number_Response
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
SELECT #SQL = 'SELECT Name, IRIS_ID__c, ' + #Columns + '
FROM
(
SELECT NAME, IRIS_ID__c, Selected, Question_Concept_With_ImpactArea__c
FROM Company_Number_Response
) s
PIVOT (
max(Unified_Response__c)
FOR Question_Concept_With_ImpactArea__c IN (' + #Columns + ')
) p
ORDER BY [IRIS_ID__c];'
EXEC sys.sp_executesql #SQL

Run SQL pre-defined function stored in table

I have a table which stores a SQL predefined function, like CONVERT(VARCHAR(10), '2012-08-21 00:16:41.993', 101) in a row/column. While retrieving the result from table, it should run the function and give the final outcome as "2012-08-21", instead right now it returns the same function statement. I am running select (select RunDate from RunDate) and using SQL server database.
Kindly help!!
You need to use dynamic SQL for this. You can't just nest expressions and have SQL evaluate the output...
DECLARE #x TABLE(sql NVARCHAR(255));
INSERT #x(sql) SELECT N'CONVERT(VARCHAR(10), ''2012-08-21 00:16:41.993'', 101)';
DECLARE #sql NVARCHAR(MAX);
SELECT #sql = N'SELECT ' + sql FROM #x;
EXEC sp_executesql #sql;
It would look like this (adjust accordingly):
DECLARE #predef VARCHAR(1000);
DECLARE #sqlquery VARCHAR(1000);
SELECT #predef = (SELECT top 1 Value FROM Parameters Where Name = 'MYFUNC');
SET #sqlquery = 'select ' + #predef + ' from SomeTable';
EXECUTE ( #sqlquery );
One tip: here be dragons. Beware of SQL Injection.