MSSQL searching unicode characthers using LIKE operator - sql

I have a stored procedure where I pass a parameter that is unicode and looks like following:
מוכר שמן קוקוס בכחל מיני ואריציות
Now the problem here is that when I enter something in my form to search for this value in m table like fllowing:
IF LEN(#SearchValue) > 0
BEGIN
SET #WhereQuery = #WhereQuery +
'(Type=' + CAST(#type AS NVARCHAR(10)) + ' and UserId=' + CAST(#userid AS NVARCHAR(10)) + ') and'
+ '(convert(nvarchar(max),SentWord) like ''%' + #SearchValue + '%'' or '
+ 'convert(nvarchar(max),Comment) like ''%' + #SearchValue + '%'')'
END
Where #SearchValue is defined as nvarchar(200) in SQL server and table columns that hold the specific value are:
SentWord and Comment and both are unicode defined as nvarchar(600).
What am I doing wrong here? Why cant MSSQL search by hebrew characthers ? Can someone help me out?
As #Jeroen stated , possible fix would be to add N after LIKE operator like following:
IF LEN(#SearchValue) > 0
BEGIN
SET #WhereQuery = #WhereQuery +
'(Type=' + CAST(#type AS NVARCHAR(10)) + ' and UserId=' + CAST(#userid AS NVARCHAR(10)) + ') and'
+ '(convert(nvarchar(max),SentWord) like N''%' + #SearchValue + '%'' or '
+ 'convert(nvarchar(max),Comment) like N''%' + #SearchValue + '%'')'
END
But it still doesn't works...

Don't concatenate your strings like that!!! It's an injection nightmare!
Next, your declaring your literal unicode string as a varchar, not an nvarchar. if you try SELECT 'מוכר שמן קוקוס בכחל מיני ואריציות'; notice the return value is '???? ??? ????? ???? ???? ????????'. You need to prefix it with N, thus: SELECT N'מוכר שמן קוקוס בכחל מיני ואריציות';.
Now, the important is parametrising that SQL... Unfortunately I don't have enough of the SQL to actually do this in full for you, so here's a different example instead:
DECLARE #SQL nvarchar(MAX);
DECLARE #string nvarchar(20) = N'Test';
SET #SQL = 'SELECT * FROM MyTable WHERE MyColumn = #dString;'; --Notice the variable in the dynamic SQL
PRINT #SQL;
EXEC sp_executesql #SQL, N'dString nvarchar(20)',#dString = #string; --Notice the variable declaration and assignment.

Related

Cast a #param in SQL Server stored procedure?

I have a SQL Server stored procedure that takes a #columnName parameter, and I am using it in building the query:
AND #columnName LIKE '%' + #userInput + '%'
If I replace the #columnName with a static value it works, like this:
AND userName LIKE '%' + #userInput + '%'
I believe this is because the #columnName is treated as string, because when running the stored procedure, it is being passed as string like that:
EXEC app.findUsers 'UserName', 'sa'
Is it possible to do it without using a dynamic query string?
You need to use SQL Dynamic to do this.
DECLARE #SQL VARCHAR(8000)
SET #SQL = 'SELECT Column FROM Table WHERE [' + #columnName + '] LIKE ''%' + #userInput + '%'''
PRINT #SQL
EXEC(#SQL)

Is there a way to Replace(*) in sql?

So simply I'm doing something similar to:
select
[BadData], [WorseDate], [IQuitData]
into
#BadDataTempTable
from
SomeoneElsesMess
what I want to do now is something similar to:
Select
Replace(#BadDataTempTable.*, ',', ' ')
from
#BadDataTempTable -- Replace all commas in every column `with a space--`
Is this possible? If so please show me the easiest (non-function) way to do so.
Thanks. SQL Server 2012 I think. I'm using SSMS 17
No, the columns have to be specified. You could use dynamic SQL to build your update / query. Then just copy the command you want from the results.
Maybe this will help get you started:
BEGIN
-- Set the replace value
DECLARE #ls_replaceValue NVARCHAR(MAX) = ',';
-- Set the with value
DECLARE #ls_withValue NVARCHAR(MAX) = ' ';
-- Set the table name we want to query
DECLARE #ls_table NVARCHAR(MAX) = 'some_table';
-- Get all of the columns and provide the replace parameters
DECLARE #ls_columns NVARCHAR(MAX) = '';
SELECT #ls_columns = #ls_columns + ', ' + name + ' = REPLACE(' + name + ', ' + '' + '''' + REPLACE(#ls_replaceValue, '''', '''''''') + '''' + ', ' + '''' + REPLACE(#ls_withValue, '''', '''''''') + '''' + ')'
FROM sys.all_columns
WHERE object_id = OBJECT_ID(#ls_table)
AND collation_name IS NOT NULL; -- Skip columns that aren't character based
-- Remove the first ', ' from the column list
SET #ls_columns = SUBSTRING(#ls_columns, 3, LEN(#ls_columns));
IF #ls_columns = ''
BEGIN
PRINT 'Table not found'
RETURN
END
-- Build a query
DECLARE #ls_query_sql NVARCHAR(MAX) = '';
SET #ls_query_sql = 'SELECT ' + #ls_columns + ' FROM ' + #ls_table;
-- Show the results
SELECT #ls_query_sql AS querySQL;
END
Just since the OP asked about how you might do this in dynamic SQL, here's how I'd approach it. Basically get the table schema information and concatenate all the columns, plus the REPLACE logic you want using FOR XML. This basically constructs the statement Rigerta posted, but does it dynamically.
use tempdb
go
if object_id('tempdb.dbo.#SomeoneElsesBadData') is not null drop table #SomeoneElsesBadData
create table #SomeoneElsesBadData
(
BadData varchar(250),
WorseData varchar(250),
IQuitData varchar(250)
)
declare #sql nvarchar(max)
select #sql = 'select '
+ stuff((select ', '
+ name
+ ' = replace(' + name + ''','', '''')'
from tempdb.sys.columns
where object_id = object_id('tempdb.dbo.#SomeoneElsesBadData')
for xml path('')), 1, 1, '')
+ ' into #BadDataTempTable
from #SomeoneElsesBadData'
exec sp_executesql #sql
All things being equal, the data should probably be cleaned before it gets into SQL, but reality is rarely fair.

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

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.

LIKE in dynamic queries

I want to use the like keyword in a dynamic parameterized query. I want to protect my query from SQL injections so I don't want to pass the value, instead I want to pass my criteria while executing the query,
Is there a way I can do this?
SELECT
ComposeMail.ID,
ComposeMail.DateTime,
ComposeMail.Subject,
ComposeMail.CreatedBy,
ComposeMail.ReceiverStatus,
Users.Name,
ROW_NUMBER() OVER(ORDER BY '+ #p_SortExpression +') AS Indexing
FROM
ComposeMail
INNER JOIN
Users
ON
ComposeMail.CreatedBy = Users.ID
WHERE
(ToReceipientID=#p)
AND (
ReceiverStatus=3
OR ReceiverStatus=4
)
AND (
(Subject Like ''%' + #p3 + '%'')
OR (Body Like ''%' + #p3 + '%'')
OR (Name Like ''%' + #p3 + '%'')
)
This is my dynamic query string. I don't want to pass the value here.
To prevent against injection in a dynamic query you always want to do something like this (instead of doing ' + #var + ' in your example)
DECLARE #query nvarchar(2000),
#paramList nvarchar(2000)
SET #query = 'SELECT * FROM dbo.Orders WHERE custLastName LIKE ''%'' + #custLastName + ''%'''
SET #paramList = '#custLastName varchar(30)'
EXEC SP_EXECUTESQL #query, #paramList, #custLastName
edit: example updated to use LIKE
WHERE (LastName LIKE N'%' + #Family + N'%') OR
(RegNo LIKE N'%' + #Codemeli + N'%')
like in dynamic sql query