While using SP_ExecuteSQL I'm generating a boolean error - sql

I'm very new to SQL, so let me first apologize if my questions come off as trivial or it seems as though I haven't done my work. I am trying to learn how to grasp a lot of these concepts.
Anyway, I'm writing a complex query that will eventually take many parameters. For these parameters I'll be using a comma delimited string to allow multiple variables. (I've solved this issue previously, but not when attempting to execute an SP_ExecuteSQL.
With that being said, here is the bare bones of the query.
DECLARE #system_status varchar(30)
SELECT #system_status = '12,14'
DECLARE #sql nvarchar(4000)
SELECT #sql = 'SELECT [system_status]
FROM VW_Document_Main
WHERE 1=1 '
IF #System_Status = '-1'
Begin
SELECT #sql = #sql + 'and system_status <> 20'
End
ELSE IF #system_status IS NOT NULL AND #system_status NOT IN ('-1','0')
Begin
SELECT #sql = #sql + 'and ' + #system_Status + ' LIKE ''%,'' + system_Status + '',%'''
I'm able to populate a useable query when not building it into an sp_executesql statement, however, since I'll be building about this query it's necessary to take these steps... any thoughts as to why I'm generating the non-Boolean error?
EDIT: Not sure if it's a step in the right direction, but now after reworking the final SELECT statement to read:
SELECT #sql = #sql + 'and '',''' + #system_Status + '',''' LIKE ''%,' + 'system_Status' + ',%'''
It's giving me back a different error: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.
It should be worth noting that the error reads: An expression of non-boolean type specified in a context where a condition is expected, near ','.

You're plugging in your literal #system_status value '12, 14' into the final SQL so it looks like this
SELECT [system_status] FROM VW_Document_Main WHERE 1=1 and 12,14 LIKE '%,' + system_Status + ',%'
Which will fail because you don't have 12,14 in quotes. So you'll have to modify the line
SELECT #system_status = '12,14'
to be
SELECT #system_status = '''12,14'''
Alternatively, since you said you're running this through sp_executeSql you should modify your last select to
SELECT #sql = #sql + 'and #system_Status LIKE ''%,'' + system_Status + '',%'''
And change your execute SQL proc to
sp_executesql #sql, N'#system_status varchar(30)', #system_status

Related

selecting a variable string name in sql select query in case of stored procedures

Suppose I want to select a constant value in an sql query, I could do something like this :
select name,age,'tick' from tableA
I want to dynamically generating an sql query using stored procedures. For example :
SELECT #SQL = 'SELECT CID,DOB, NAME, '+#Scname+' from ' + #TableName
Where #TableName, #Scname are dynamically generated variables in a while loop. Here #Scname is interpreted as a column name instead of a constant string when executing query on #TableName. I have tried using escape characters as follows :
SELECT #SQL = 'SELECT CID,DOB, NAME, \"'+#Scname+'\" from ' + #TableName
But it returns a floating point value full of zeros instead of the string contained in #Scname.
I think following should work
SET #SQL = 'SELECT CID,DOB, NAME,'+''''+#Scname+''''+' from '+ #TableName
Try
SELECT #SQL = 'SELECT CID,DOB, NAME,' + QUOTENAME(#Scname, '''') + ' from ' + #TableName

How to use LIKE in dynamic SQL in a stored procedure?

I wrote a stored procedure using dynamic SQL:
create procedure [dbo].[SearchProduct]
(#ProductId int = null, #ProductName nvarchar(50) = null)
as
declare #SqlStr nvarchar(max)
declare #ParaList nvarchar(2000)
set #SqlStr = 'select p.* from dbo.Product where (1=1) '
if #ProductName is not null
set #SqlStr = #SqlStr + 'and(p.ProductName like '''%' + #ProductName2+'%''')'
set #ParaList='#ProductId2 int , #ProductName2 nvarchar(50)'
EXECUTE SP_EXECUTESQL #SqlStr,#ParaList,#ProductId,#ProductName
But I get an error:
Error in "Like operator" : The data types varchar and varchar are incompatible in the modulo operator.
If I change :
set #SqlStr = #SqlStr + 'and(p.ProductName like ''%' + #ProductName2+'%'')'
I get:
#ProductName2 not declare.
Since you look new to this please accept these notes from me:
As for your question... Your select statement ends with where and you follow it with and
select p.* from dbo.Product where '
Also before % you should have only 2 single quotes not 3.. Like ' '%' +.... + '%' '...
When you do dynamic sql procedures,,, always use print() method first instead of exec to evaluate your sql.
Use case when statement instead of if statements. it will organize your Code much better.
Since dynamic sql is really very bad practice ... Your question should be "how to convert this procedure to normal sql instead of dynamic..."
At the end, please accept my apologies for the lack of samples, mistakes and help links as am answering from my mobile phone.
You have a quote or two too many:
if #ProductName is not null
set #SqlSt r = #SqlStr + 'and (p.ProductName like ''%' + #ProductName2+'%'')';
Within a string, two single quotes represent one single quote in the string. The third single quote then ends the string.
should be below. You have the single quote wrongly
if #ProductName is not null
set #SqlStr=#SqlStr+'and(p.ProductName like ''% + #ProductName2 + %'')'

Using table columns in prepared statement parameter

My page has a dropdown list that let a user choose any search category like title, description and so forth. So I have this SQL statement:
select * from table where "selected value from dropdown list" = "searchform"
I would like to pass it to the prepared statement like this:
select * from table where ? = ?
Since my select statements have the same form, only the columns in the where clause are different, is there a way to do this without manually creating select statements for every column?
Yes, it is called dynamic sql.
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + #column + ' = ''' + #value + ''''
EXEC(#sql)
You must check if the column is of numeric type.
You should also be careful for sql injection. My example is a very simplistic one, so you have to do your own checks.
For instance use of QUOTENAME would be useful:
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + QUOTENAME(#column) + ' = ''' + #value + ''''
EXEC(#sql)
The above examples are simply TSQL. In your prepared statement i think you could have the following:
PreparedStatement pstmt = con.prepareStatement("
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'select * from table where ' + QUOTENAME(?) + ' = ? '
EXEC(#sql)
");
pstm.setString(1,columnName);
pstm.setString(2,filterValue);
Unfortunately i am not familiar with JAVA, so i have not tested this. I think it worths a try though.
The above #sql variable will produce a statement like :
select * from table where [columnname] = filtervalue
columnname wrapped with brackets will help against SQL injection.

dynamic sql and how to escape special characters?

I have a stored procedure which searches for names based on a string.
if I pass in #SearchTerm as the following value: o'clock
SET #NameSearch = ' (CONTAINS(lmc.Name,''"*' + REPLACE(#SearchTerm,'''','''''') + '*"'')) '
#NameSearch would be set to:
"*o''clock*"
this would return no rows.
however if I just pass in 'clock' then I will get all the results which have a name that contains the word 'clock'.
could someone explain to me how I would be able to escape the ' properly.
You should use parametrized query. Here's an example:
DECLARE #sql nvarchar(max), #paramlist nvarchar(max)
SELECT #sql= 'SELECT Test_Name
FROM [Test]
WHERE (1 = 1)'
SELECT #sql = #sql + ' AND (Test_Name LIKE (#Name + ''Toto''))'
SELECT #paramlist = '#Name nvarchar (256)'
EXEC sp_executesql #sql, #paramlist, #SearchTerm
1. You wrote
if #NameSearch would be set to: "*o''clock*" , but I guess you mean #SearchTerm
2.
What is the result of
SELECT * FROM sys.dm_fts_parser ('"*o''clock*" ', 1033, 0, 0)
One, two or three rows? May be you have problems with wordbreakers. Setup your language first, possibly it is not English (1033).
3.
If I would need to run it dynamically, then I would double apostrophes once more:
DECLARE #sql nvarchar(max)= 'SELECT * FROM sys.dm_fts_parser (''"*o''''clock*" '', 1033, 0, 0)'
exec(#sql)
That is ok, but since you are going to automatically double apostrophes, then you could put extra apostrophes just by error.. Possibly you should dig this direction or present us clear code snippet.

Checking whether conditions are met by all rows with dynamic SQL

I have a table in SQL Server 2008 which contains custom validation criteria in the form of expressions stored as text, e.g.
StagingTableID CustomValidation
----------------------------------
1 LEN([mobile])<=30
3 [Internal/External] IN ('Internal','External')
3 ([Internal/External] <> 'Internal') OR (LEN([Contact Name])<=100)
...
I am interested in determining whether all rows in a table pass the conditional statement. For this purpose I am writing a validation stored procedure which checks whether all values in a given field in a given table meet the given condition(s). SQL is not my forte, so after reading this questions this is my first stab at the problem:
EXEC sp_executesql N'SELECT #passed = 0 WHERE EXISTS (' +
N'SELECT * FROM (' +
N'SELECT CASE WHEN ' + #CustomValidationExpr + N' THEN 1 ' +
N'ELSE 0 END AS ConditionalTest ' +
N'FROM ' + #StagingTableName +
N')t ' +
N'WHERE t.ConditionalTest = 0)'
,N'#passed BIT OUTPUT'
,#passed = #PassedCustomValidation OUTPUT
However, I'm not sure if the nested queries can be re-written as one, or if there is an entirely better way for testing for validity of all rows in this scenario?
Thanks in advance!
You should be able to reduce by at least one subquery like this:
EXEC sp_executesql N'SELECT #passed = 0 WHERE EXISTS (' +
N'SELECT 1 FROM ' + #StagingTableName +
N'WHERE NOT(' + #CustomValidationExpr + N')) ' +
,N'#passed BIT OUTPUT'
,#passed = #PassedcustomValidation OUTPUT
Before we answer the original question, have you looked into implementing constraints? This will prevent bad data from entering your database in the first place. Or is the point that these must be dynamically set in the application?
ALTER TABLE StagingTable
WITH CHECK ADD CONSTRAINT [StagingTable$MobileValidLength]
CHECK (LEN([mobile])<=30)
GO
ALTER TABLE StagingTable
WITH CHECK ADD CONSTRAINT [StagingTable$InternalExternalValid]
CHECK ([Internal/External] IN ('Internal','External'))
GO
--etc...
You need to concatenate the expressions together. I agree with #PinnyM that a where clause is easier for full table validation. However, the next question will be how to identify which rows fail which tests. I'll wait for you to ask that question before answering it (ask it as a separate question and not as an edit to this one).
To create the where clause, something like this:
declare #WhereClause nvarchar(max);
select #WhereClause = (select CustomValidation+' and '
from Validations v
for xml path ('')
) + '1=1'
select #WhereClause = replace(replace(#WhereClause, '<', '<'), '>', '>'))
This strange construct, with the for xml path('') and the double select, is the most convenient way to concatenate values in SQL Server.
Also, put together your query before doing the sp_executesql call. It gives you more flexibilty:
declare #sql nvarchar(max);
select #sql = '
select #passed = count(*)
from '+#StagingTableName+'
where '+#WhereClause
That is the number that pass all validation tests. The where clause for the fails is:
declare #WhereClause nvarchar(max);
select #WhereClause = (select 'not '+CustomValidation+' or '
from Validations v
for xml path ('')
) + '1=0'