Dynamic SQL Query: Replace all single quotes to double quote - sql

I have a dynamic SQL query and some params are being passed in such as this
Set #SQL = 'Update Table1 Set Status = 1 Where ' +
'Name = ''' + Cast(#Name As Varchar(50)) + '''' +
' Product = ''' + Cast(#Product As Varchar(50)) + ''''
I have issues with the single quote being passed in the param. If the #Name and #Product has no single quote at all, I won't have any issue. But sometimes the #Name or #Product would have single quote and that causes failure to execute my dynamic query as it's not properly formatted because of the additional single quote.
I have lots more param other than #Name and #Product, and I don't want to do something like REPLACE(#Name, '''','''''') for every single param unless it's necessary.
Is there a way that I can replace every single quote to double in my dynamic query before execution or better alternative?

Alternative but more hard work here:
Set #SQL = 'Update Table1 Set Status = 1 Where ' +
'Name = Cast(#Name As NVarchar(50)) ' +
' Product = Cast(#Product As NVarchar(50)) '
EXEC sp_executesql #SQL , N'#Name NVARCHAR(50), #Product NVARCHAR(50)', #Name, #Product
Let me know, if this worked for you ?

Related

SQL Using parameter in WHERE statement

Think I am missing something really obvious but I want to use a parameter in a where statement but when I do I get the following error (This is being run as a stored procedure if that makes any difference)
Invalid column name 'John'
The where statement in question
USE [Reports]
GO
/****** Object: StoredProcedure [Reports].[Alarm_TestSignOffFull_Qry] Script Date: 25/10/2018 08:56:26 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [Reports].[CustomerSearch]
-- Add the parameters for the stored procedure here
#Database VARCHAR(20)
,#Schema VARCHAR(20)
,#Name VARCHAR(20)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
EXEC ('
USE ' + #Database + '
SELECT Customer.Name,
[Product Categories].[Product Number]
RIGHT JOIN ((' + #Schema +'.Customer INNER JOIN ' + #Schema +'.Client ON Customer.Name = Client.Name)
LEFT JOIN ' + #Schema +'.Product ON Client.Name = Product.Client)
ON [Product Categories].[Product Number] = Client.Product
WHERE (Customer.Name = ' + #Name + ' AND Customer.Order = ''Y'') OR (Client.Name = ' + #Name + ' AND Customer.Order = ''Y'');
' )
END
GO
The parameter #Name is declared as VARCHAR(20)
Dont think too much about it had to find and replace table names and column names and stuff to make sure I am allowed to post it.
The select on the real thing also brings through a lot more fields but not too worried about that for this question
To emphasize it is the where statements that are going wrong the rest of the query works and it all works when I do not use any parameters
I'm posting this as answer, as the comments aren't enough to explain, however, there is far too little detail here to actually answer the OP's question.
Firstly, the error the OP is getting would be impossible to get with the tiny amount of SQL they have provided. If we expand it into a full Pseudo-SQL query, we get:
SELECT {Columns}
FROM Customer
WHERE Customer.Name = (' + #Name + ');
This would return rows in the Customer table, where Name has the literal string value ' + #Name + '. Very unlikely.
I suspect that the OP simply needs to do:
SELECT {Columns}
FROM Customer
WHERE Customer.Name = #Name;
HOWEVER, the error the OP is getting strong implies they are using Dynamic SQL. This means they have a query like this:
DECLARE #SQL nvarchar(MAX);
DECLARE #Name varchar(20) = 'John';
SET #SQL = N'SELECT {Columns} FROM Customer WHERE Customer.Name = (' + #Name + ');';
EXEC (#SQL);
The problem here is that translates into the SQL:
SELECT {Columns} FROM Customer WHERE Customer.Name = (John);
Notice, no quotes around John, and why the error.
What you are doing here, however, is a very bad idea. Raw string concatenation like that leaves your SQL wide open to injection(SQL injection). Parametrise your SQL:
DECLARE #SQL nvarchar(MAX);
DECLARE #Name varchar(20) = 'John';
SET #SQL = N'SELECT {Columns} FROM Customer WHERE Customer.Name = #dName;'
EXEC sp_executesql #SQL, N'#dName varchar(20)',#dName = #Name;`
Edit: Ok, the OP has provided us with their query. Honestly, it's a mess, far worse that I wanted it to be. Like i said before, raw string concatenation is an awful idea, it leaves you open to injection. You can't get rid of concatenation for dynamic objects, but you can use QUOTENAME, which makes the code safe(r).
You're also missing a FROM; no idea what that needs to be, so i've left that as pseudo-sql. That RIGHT JOIN is very messy too, but I've no idea what you're trying to achieve there.
Anyway, this need to replace your EXEC command. Read the below, understand the below, and don't make the mistake of concatenating raw strings in your dynamic SQL:
DECLARE #SQL nvarchar(MAX)
SET #SQL = N' USE ' + QUOTENAME(#Database) + N';' + NCHAR(10) +
N'SELECT Customer.Name,' + NCHAR(10) +
N' [Product Categories].[Product Number]' + NCHAR(10) +
--where is your FROM?
N'FROM {Something}' + NCHAR(10) + --This needs fixing
N' RIGHT JOIN((' + QUOTENAME(#Schema) + N'.Customer' + NCHAR(10) + --This whole thing is messy, but i'm not fixing it, as I have no data
N' INNER JOIN ' + QUOTENAME(#Schema) + N'.Client ON Customer.Name = Client.Name)' + NCHAR(10) +
N' LEFT JOIN ' + QUOTENAME(#Schema) + N'.Product ON Client.Name = Product.Client)ON [Product Categories].[Product Number] = Client.Product' + NCHAR(10) +
N'WHERE (Customer.Name = #dName' + NCHAR(10) +
N' AND Customer.[Order] = ''Y'')' + NCHAR(10) +
N' OR (Client.Name = #dName' + NCHAR(10) +
N' AND Customer.[Order] = ''Y'');';
EXEC sp_executesql #SQL, N'#dName varchar(20)', #dName = #Name;
If you are directly write in sql then you can use as below
WHERE Customer.Name = #Name
You are using a Dynamic SQL, and if you print your query it will be like
WHERE Customer.Name = (John)
And that's wrong, you can do like
EXECUTE sp_executesql N' ..WHERE Customer.Name = #CName',
N'#CName VARCHAR(20)',
#CName = 'John';
Or even
--#Name should be declared and has 'John' value
EXECUTE sp_executesql N' ..WHERE Customer.Name = #CName',
N'#Name VARCHAR(20)',
#Name = #Name;
Why does SQL think that the parameter is a column and not just plain text?
Well, as you can see before, the parameter you pass will be John not 'John', thus SQL Server will think it's a column name.
try giving single quotes in where clause
WHERE (Customer.Name = ''' + #Name + ''' AND Customer.Order = ''Y'')
OR (Client.Name = ''' + #Name + ''' AND Customer.Order = ''Y'');

SQL Server: correct escaping Where clause in dynamic procedure (2)

I have a dynamic procedure where I want to use the below as part of my Where clause (everything else works as intended).
Currently this creates the following error: Incorrect syntax near the keyword 'LIKE'
AND CASE WHEN ' + #searchCategory + ' <> ''dateRec'' THEN
(R.' + #searchCategory + ' LIKE ''%' + #searchTerm + '%'')
ELSE
(R.dateRec = ' + CONVERT(VARCHAR, #searchTerm, 111) + ')
END
What would the proper escaping look like here ?
I believe this is what you're looking for:
declare #sql nvarchar(max), #searchCategory nvarchar(max), #searchTerm nvarchar(max)
set #searchCategory = 'dateRec'
set #searchTerm = 'yyy'
set #sql =
'AND (
(''' + #searchCategory + ''' <> ''dateRec'' AND (R.' + #searchCategory + ' LIKE ''%' + #searchTerm + '%''))
OR
(''' + #searchCategory + ''' = ''dateRec'' AND (R.dateRec = ''' + CONVERT(VARCHAR, #searchTerm, 111) + '''))
)'
print #sql
Assuming the contents of #searchCategory don't actaully contain the characters '...
SET #sql = 'AND ' +
CASE WHEN #searchCategory <> 'dateRec' THEN
'(R.' + #searchCategory + ' LIKE ''%'' + #searchTerm + ''%'')'
ELSE
'(R.dateRec = CONVERT(VARCHAR, #searchTerm, 111))'
END
This will give either....
AND (R.foobar LIKE '%' + #searchTerm + '%')
or...
AND (R.dateRec = CONVERT(VARCHAR, #searchTerm, 111))
This means that you would still pass #searchTerm to sp_executesql as a parameter, so as to protect you from SQL Injection attacks.
You DO NOT want to directly embed a user's free form text in to your SQL. Free form text must stay as a parameter in order to close that security hole.
(I'm also assuming that you have a white-list of valid values of #searchCategory so as to prevent that from being abused with an SQL Injection Attack?.)
EDIT :
An example of dynamic sql that maintains parameterisation....
DECLARE #SQL nvarchar(500);
SET #SQLString = N'SELECT * FROM table WHERE ' + #param1 + ' = #param;';
EXECUTE sp_executesql
#SQL,
'#param NVARCHAR(500)',
#param2
Using this method, you need to check that #param1 really is a legitimate field name, using a white-list for example, but you do not need to check #param2. This is because #param2 is being passed to sp_executesql as a parameter itself. It's just like dynamically making a stored procedure with parameters, rather than embedding all your values in the sql string, which lays you open to serious sql injection attacks.
EDIT :
This is not a case of embedding a LIKE statement within a CASE statement. What is being done here is creating a string that creates the string literal LIKE, by using a CASE statement.
It is much the same as this...
SET #sql = 'AND ' +
CASE WHEN #searchCategory <> 'dateRec' THEN
'A string with the word' + ' LIKE ' + 'in it'
ELSE
'A different string without that word in it'
END

SQL Dynamic Query String Breaks When Variable Contains Single Quote

I have a SQL query string that is like this:
DECLARE #sql varchar(max)
SET #sql = ' INSERT INTO ' + #tempTable1 +
' SELECT 0 as Type1, 0 as Type2, ' +
'''' + #name + ''' as CompanyName ' +
' FROM #tempTable2 tt2'
The query runs fine except for two names that happen to contain a single quote (ex: Pete's Corner). When either one of these names becomes part of the query it breaks the query string. I thought the easiest thing to do would be to replace the single quote like this replace(#name,'''','') but it doesn't work because I'm already in a string and so its affecting the rest of the statement. Altering the table itself is not an option unfortunately.
How can I replace or remove these single quotes?
Addition: I apologize, I did not include the part where #name is actually being populated from another database table by a join so setting the value of #name before the string is created I think would be difficult for me.
Why do you need to do this at all? You should be passing strong parameters to sp_executesql instead of munging all of your parameters into a single string and using EXEC(). More info on that here.
DECLARE #sql NVARCHAR(MAX), #name NVARCHAR(32);
SET #name = 'Pete''s Corner';
SET #sql = 'INSERT INTO ' + #tempTable1 +
' SELECT 0 as Type1, 0 as Type2, #name as CompanyName ' +
' FROM #tempTable2 tt2';
EXEC sp_executesql #sql, N'#name NVARCHAR(32)', #name;
I presume the #name parameter actually gets populated from elsewhere, and if using proper parameterization you shouldn't have to deal with escaping the '.
Now I'm not quite sure what #tempTable1 is supposed to represent, or if you can access #tempTable2 from this scope, but whenever you find yourself running a replace that requires '''' or '''''' (or both), you should ask yourself if maybe there's a better way.
I think this should do it:
DECLARE #sql varchar(max)
SET #sql = ' INSERT INTO ' + #tempTable1 +
' SELECT 0 as Type1, 0 as Type2, ' + ''''+
replace( #name ,'''','''''')+''''+' as CompanyName
FROM #tempTable2 tt2'
You can use sp_executesql system procedure. sp_executesql will allow you to call dynamic SQL with #name parameter instead of embedding it into the SQL.
DECLARE #sql nvarchar(max),
#name varchar(50)
SET #name = 'qwe'''
SET #sql = 'INSERT INTO ' + #tempTable1 +
' SELECT 0 as Type1, 0 as Type2, ' +
'#name as CompanyName ' +
'FROM #tempTable2 tt2'
--PRINT #sql
EXEC sp_executesql #sql, N'#name varchar(50)', #name

Conversion failed when converting value in dynamic sql statement

I'm stuck on the following sql server:
DECLARE #sql AS NVARCHAR(500),#db as varchar(50),#value AS CHAR(129);
SET #db = 'SSCT1';
SET #value = '1806-11-801-1000';
SET #sql = 'SELECT ACTINDX FROM ' + quotename(#db)
+ '.[dbo].[GL00105] WHERE ACTNUMST = ' + #value;
EXEC (#sql);
When I run this in sql server I get :
Conversion failed when converting the varchar value '1806-11-801-1000
I checked the field I'm using the where clause against and it matches the type in the declaration (char(129) so I'm not sure what it's trying to convert.
I'm trying to build a sql statement that will accept the db name as a variable in addition to the value. any thoughts?
thanks
I'm going to guess that ACTNUMST is a string column, in which case you need to delimit it correctly:
SET #sql = 'SELECT ACTINDX FROM ' + quotename(#db)
+ '.[dbo].[GL00105] WHERE ACTNUMST = '''
+ #value + ''';';
If #value might ever contain apostrophes, you need to deal with that further:
SET #sql = 'SELECT ACTINDX FROM ' + quotename(#db)
+ '.[dbo].[GL00105] WHERE ACTNUMST = '''
+ REPLACE(#value, '''', '''''') + ''';';
Yuck. A much safer approach is:
DECLARE
#sql NVARCHAR(MAX),
#db SYSNAME,
#value CHAR(129);
SELECT
#db = N'SSCT1',
#value = '1806-11-801-1000';
SET #sql = N'SELECT ACTINDX FROM ' + quotename(#db)
+ '.[dbo].[GL00105] WHERE ACTNUMST = #val;';
EXEC sp_executesql #sql, N'#val CHAR(129)', #value;
This guards a little better against dynamic SQL and also prevents you from having to deal with the quotes.
This could happen because you didn't quote the char value. Try this
SET #sql = 'SELECT ACTINDX FROM ' + quotename(#db) + '.[dbo].[GL00105] WHERE ACTNUMST = ''' + #value + '''';
Does this fail when you try to execute the SQL? Or if you comment the EXEC call out, does it still fail?
One thing that catches my eye, is that you don't have any single quotes around your #value. So when the #sql is built, it will end up building it as ...
WHERE ACTNUMST = 1806-11-801-1000
however, it should look like this...
WHERE ACTNUMST = '1806-11-801-1000'
If this is indeed your issue, then you should modify your SET #sql to the following...
SET #sql = 'SELECT ACTINDX FROM ' + quotename(#db) + '.[dbo].[GL00105] WHERE ACTNUMST = ''' + #value + '''';
This will add the single quotes to your dynamic sql statement. I hope this helps.

SQL query not showing columns in DataSet in Visual Studio

I have a stored procedure in SQL Server 2008. I declare an #query param via DECLARE #query NVARCHAR(MAX), I then set this #query according to the type of data sent in and then I use exec [sys].[sp_executesql] #query to execute the stored procedure.
The problem I'm having is that I'm using a DataSet in Visual Studio, that links to this stored procedure (used on a report).
When I do my stored procedure in this manner (with the #query), then the dataset does not pick up the column data to show. I had to create the stored procedure this way (with #query), because I need the where clause to be different depending on the data sent in.
My code:
CREATE PROCEDURE [dbo].[p_Test_GetFooData]
#pName VARCHAR(250) = '',
#pID INT = NULL
AS
BEGIN
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT FOO.FirstName, FOO.LastName
FROM Test.FooOne AS FOO'
IF ( #pName = '--- SELECT ---' )
BEGIN
SET #query = #query + ' WHERE FOO.ID = '
+ CONVERT(VARCHAR(50), #pID) + ''
END
ELSE
BEGIN
SET #query = #query + ' WHERE FOO.ID = '
+ CONVERT(VARCHAR(50), #pID) + ' AND
PP.FirstName + LIKE ''%' + #pName
+ '%'' '
END
EXEC [sys].[sp_executesql] #query
END
I have tested the query and it returns the correct data when I run the stored procedure. When I don't use SET #query = 'SELECT STATEMENT' EXEC #query then the dataset works as it should.
Any help will be appreciated.
Another option is to write the query in a different way eg.
SELECT FOO.FirstName,
FOO.LastName
FROM Test.FooOne AS FOO
WHERE FOO.ID = #pID
and PP.FirstName LIKE case when #pName = '--- Select ---' then PP.FirstName else '%' + #pName + '%' end
This will always compare Foo.ID to #pID
and will either compare pp.FirstName to itself (always returning true) or wil