Filter fields in 'IN' clause using a variable - sql

I would like to do something like this :
DECLARE #list nvarhcar(200) SET #list = 'VALUE1,VALUE2,VALUE3'
Select * from foo where field in (#list)
Until today I solved using sp_executeSQL procedure, my own database function csv2table and subselect, but I think that is not very clean.
Is there any way to solve without use dynamic sql ? Is there a direct method?
I'm using Microsoft Sql Server 2005.
Thanks!

Would you please try as below: thanks
DECLARE #list nvarchar(200)
SET #list = 'VALUE1,VALUE2,VALUE3'
SELECT * FROM foo WHERE CHARINDEX(',' + field + ',', ',' + #list + ',') > 0

Create Part A as an UDF
/* Part A */
DECLARE #list Varchar(max) = 'VALUE1,VALUE2,VALUE3'
DECLARE #tmpTbl_Values Table (ID varchar(50))
Set #list = #list + ','
-- Indexes to keep the position of searching
Declare #Pos1 Int
Declare #pos2 Int
-- Start from first character
Set #Pos1=1
Set #Pos2=1
While #Pos1<Len(#list)
Begin
Set #Pos1 = CharIndex(',',#list,#Pos1)
Insert #tmpTbl_Values Select Cast(Substring(#list,#Pos2,#Pos1-#Pos2) As varchar(50))
-- Go to next non comma character
Set #Pos2=#Pos1+1
-- Search from the next charcater
Set #Pos1 = #Pos1+1
End
/* Part B */
SELECT *
FROM foo A
INNER JOIN #tmpTbl_Values B
ON AB.ID = B.ID

One alternative:
Select * from foo where '%,' + field + ',%' like ',' + (#list) + ','
This is even "dirtier" than the existing approach.
Ideally, I would suggest changing the query string to:
Select * from foo where field in ()
then reading through the list of values in #list, inserting a ? for each value (separated by commas) and binding each value to that parameter marker. However, I don't know how to achieve this in dynamic SQL alone.

If the datatype for the field is nchar or varchar, the IN() operator will look for value like
IN('VALUE1','VALUE2','VALUE3', etc..)
So you set your #list based on that

A possible approach is to do the following:
SELECT * FROM foo WHERE CHARINDEX(',' + field + ',', ',' + #list + ',') > 0
This is assuming that the data in the field has no comma in it

If you deal with a string field, you could use something like this..
DECLARE #csv varchar(50) = 'item1,item2, item3, item4 ,item5'
SELECT * FROM foo WHERE PATINDEX('%' + Field + '%', #csv) > 0

In SQL 2005 you can use a custom UDF to parse a delimited list into a table - please see this article http://www.sommarskog.se/arrays-in-sql-2005.html

Related

The argument 1 of the XML data type method “value” must be a string literal

If i pass #count variable i am getting this error
Below is my query
DECLARE #Error_Description NVARCHAR(Max)
DECLARE #Count VARCHAR(20)
DECLARE #x NVARCHAR(Max)
SELECT #Error_Description = 'The external columns for Excel Source are out of synchronization with the data source columns.
The column "szReferencceNumber" needs to be added to the external columns.
The column "SMSa" needs to be added to the external columns.
The column "as" needs to be added to the external columns.'
SELECT #Count = (LEN(#Error_Description) - LEN(REPLACE(#Error_Description, '"', ''))) / LEN('"')
SELECT #Count
SELECT COALESCE(LTRIM(CAST(('<X>' + REPLACE(#Error_Description, '"', '</X><X>') + '</X>') AS XML).value('(/X)[' + #Count + ']', 'varchar(128)')), '')
The first parameter to value must be a string literal. To select the nodes with a dynamic index you can do the following
SELECT
n.value('.', 'varchar(128)') as Result
from (SELECT CAST(('<X>' + REPLACE(#Error_Description, '"', '</X><X>') + '</X>') AS XML)) ca(x)
CROSS APPLY x.nodes('(/X)') n(n)
WHERE n.value('for $l in . return count(../*[. << $l]) + 1', 'int') %2 = 0
This returns the value for every second node. So achieves your desired results of getting the values enclosed in quotes.
Result
---------------------
szReferencceNumber
SMSa
as
if you're using 2012+, and you can use nvarchar(4000) (not MAX), you could get a copy of DelimitedSplitN4K_LEAD and grab rows where the value of ItemNumber is even:
DECLARE #Error_Description nvarchar(4000);
SELECT #Error_Description = N'The external columns for Excel Source are out of synchronization with the data source columns.
The column "szReferencceNumber" needs to be added to the external columns.
The column "SMSa" needs to be added to the external columns.
The column "as" needs to be added to the external columns.';
SELECT DS.Item
FROM dbo.DelimitedSplitN4K_LEAD(#Error_Description,'"') DS
WHERE DS.ItemNumber % 2 = 0;
If you're on SQL server 2016+, then you could use some JSON manipulation (which supports MAX values):
SELECT OJ.value
FROM (VALUES(#Error_Description))V(Error_Description)
CROSS APPLY (VALUES('["' + REPLACE(REPLACE(REPLACE(V.Error_Description,'"','","'),NCHAR(13),''),NCHAR(10),'')+ '"]'))R(JSON)
CROSS APPLY OPENJSON(R.JSON) OJ
WHERE OJ.[Key] % 2 = 1;
You can use your #Count within the XQuery predicate, but not via concatenation. There is sql:variable():
TheXml.value('(/X)[sql:variable("#Count") cast as xs:int?][1]', 'varchar(128)')
It would help to declare the variable #Count as INT in order to avoid the XQuery cast.
Hint: You need the final [1] to enforce the singleton .value() demands for.
this is all based on the #Shnugo answer above, thanks a lot Shnugo
I have a long script saved in to a temp table
select * from #Radhe
I want to print the whole script.
DECLARE #SQL NVARCHAR(MAX)
DECLARE #XML3 XML
--load the script to XML
SELECT #XML3 = (SELECT #Radhe.Item AS x FROM #Radhe FOR XML PATH(''))
--print line by line
declare #i int = 1
select #sql = 'radhe'
while #sql is not null
begin
SELECT #sql = #xml3.value('(/x/text())[sql:variable("#i")
cast as xs:int?][1]', 'varchar(max)')
print #sql
select #i = #i + 1
if #i > 10000 --limit it to 10000 lines
set #sql = null
end
and it works.
It took me a long time to get this done.
Hope I can help a fellow DBA or developer.

How to get result with square bracket surrounded to each value when using IN keyword in Pivot table?

I am writing the sql query for creating the pivot table. I have the sample code where I am getting the result without error but the result should be values surrounded by square bracket to each value instead to the whole result. How do I setup for it?
I have tried using quote function but it is putting square bracket around the whole output.
DECLARE #CityNames NVARCHAR(MAX) = '', #t varchar(max) = 'jay, sam'
SELECT #CityNames += QUOTENAME(#t)+ ','
select #CityNames
I expect the output to be [jay],[sam], but the actual output is [jay,sam].
Is this what you want?
select '[' + #t + replace(#t, ', ', '], [') + ']')
QUOTENAME() treats the string as a single identifier, quoting appropriately The above should work for most reasonable column names.
I have found the answer by using QUOTENAME() function, we can follow the below code or above code by #gordon Linoff.
DECLARE #CityNames NVARCHAR(MAX) = '', #t nvarchar(max) = 'jay, sam', #result
varchar(max), #sSQL nvarchar(max)
SELECT #CityNames += + QUOTENAME(value)+',' from (select value from
dbo.fx_split( #t, ','))x
IF (RIGHT(#CityNames, 1) = ',')
set #CityNames = LEFT(#CityNames, LEN(#CityNames) - 1)
select #citynames

query not retrieving values returned from split string

I generate comma seperated string and add single quite to each numbers
Here is how i do it
DECLARE #IDs NVARCHAR(max)
SELECT #IDs = COALESCE(#IDs +',', '') + ''''
+ Cast([mynos] AS NVARCHAR(255)) + ''''
FROM mytable
WHERE id = 22
If i print variable #IDs then i get below output
'78888','3333','1222'
When i use same variable in this query then query doesnt return any value
SELECT *
FROM table1
WHERE ids IN ( #IDs )
How to fix this?
It doesn't work as your query is effectively doing this:
SELECT *
FROM TABLE
WHERE Ids IN ('''78888'',''3333',''1222''');
Which would also be equivalent to:
SELECT *
FROM TABLE
WHERE Ids = '''78888'',''3333',''1222''';
If you want to do the query as you have done, you'll need to split your delomited data out again. As you're using SQL Server 2012, you can't make use of STRING_SPLIT, so you'll need to a different one; such as Jeff Moden's DelimitedSplit8K. Then you can do:
SELECT *
FROM TABLE
WHERE IDs IN (SELECT items
FROM dbo.DelimitedSplit8K (#IDs,','));
However, why are you not simply doing...
SELECT *
FROM TABLE T
WHERE EXISTS (SELECT 1
FROM myTable mT
WHERE mT.Id = 22
AND mT.myNos = T.Ids);
You can use dynamic query #id is string variable not multi-value argument
DECLARE #IDs nVARCHAR(MAX)
SELECT #IDs = COALESCE(#IDs +',' ,'') + '''' + CAST([myNos] AS nVARCHAR(255)) + ''''
FROM myTable WHERE Id = 22
DECLARE #query nVARCHAR(MAX)
SET #query = "Select * from table1 where Ids in ("+#IDs+")"
EXECUTE sp_executesql #query
I tried below and it worked
select * from table1 where id in (select mynos from mytable where id = 22)
Thanks to #Larnu for giving me idea

Read each string that follows a char in sql

So let us say you have a string:
set #string = 'aaa,2,dqw,3,asdad,5,4'
I would like to read the chars that are after a char and a ","
So the result to this string would be:
Result
--------
2
3
5
How could I do this?is there a way to use CHARINDEX for this?
If your string is just like your example, using Charindex(',', <string>) works too.
Otherwise, use PATINDEX. It functions similarly,but you can also set it to recognize all numeric characters.
IF PATINDEX('%[0-9]%', #String') <> 0
THEN BEGIN
SET #string = SUBSTRING(#string, PATINDEX('%[0-9]%', #string), LEN(#string) )
SET #var = SUBSTRING(#string, PATINDEX('%[^0-9]%', #string) )
END
you now can do as you please with those variables.
To your exception, just use one more case statement and rid of it. No reason the code has to be too complicated.
One more Approach using numbers table and split string functions
declare #string varchar(max)
set #string = 'aaa,2,dqw,3,asdad,5,4'
;with cte
as
(
select * from [dbo].[SplitStrings_Numbers](#string,',')
)
select
* from cte where isnumeric(item)=1
Output:
2
3
5
4
if you are sure about no special characters in your data..You can use above,,but some times using NUMERIC tends to show some characters as numbers
SELECT
ISNUMERIC('123') as '123' --1
,ISNUMERIC('.') as '.' --Period ---1
,ISNUMERIC(',') as ',' --Comma ---1
In this case,you can use TRY_Parse available from SQL server 2012..
declare #string varchar(max)
set #string = 'aaa,2,dqw,3,asdad,5,4'
;with cte
as
(
select b.* from [dbo].[SplitStrings_Numbers](#string,',') a
cross apply
(select try_parse(a.item as int) ) b(val)
)
select
* from cte where val is not null

How to deal space in search keywords? i want to match results by AND

I got a searchbox, the sql statment is like:
SELECT ..... WHERE ... LIKE '%A%'
but when user entered "A B" (space between A and B)
I want to select all records which content contains both A and B.
But I can not write:
.... LIKE '%A%B%'
because it won't match string that B occurs first like: "ilikeBnotA"
It should be
...LIKE '%A%' AND ...LIKE '%B%'
But the user may input more than one spance, like "A B C ...", so i need to write a loop, contacting every keyword into:
AND ...LIKE '%keyword%'
I don't think it's a good idea, i doubt it may cause performance issues when searching large string (like a blog post content).
Is there any good solution to this problem? Dow do search engines do that?
First you need a split function:
CREATE function [dbo].[f_split]
(
#param nvarchar(max),
#delimiter char(1)
)
returns #t table (val nvarchar(max), seq int)
as
begin
set #param += #delimiter
;with a as
(
select cast(1 as bigint) f, charindex(#delimiter, #param) t, 1 seq
union all
select t + 1, charindex(#delimiter, #param, t + 1), seq + 1
from a
where charindex(#delimiter, #param, t + 1) > 0
)
insert #t
select substring(#param, f, t - f), seq from a
option (maxrecursion 0)
return
end
Then you can search like this:
-- declaring a tablevariable to represent your table
declare #yourtable table(id int identity(1,1), searchcol varchar(50))
insert #yourtable values('abc')
insert #yourtable values('za')
insert #yourtable values('az')
insert #yourtable values('zz')
declare #input varchar(50)
set #input = 'a b c'
-- show if one or more match exists
select * from #yourtable a
where exists (select 1 from f_split(#input, ' ') b
where a.searchcol like '%'+ b.val + '%')
--show only if all matches exists
select * from #yourtable a
where not exists (select 1 from clausens_base.dbo.f_split(#input, ' ') b
where not a.searchcol like '%'+ b.val + '%')
You can use regular expressions with SQL and write a regex to match all given strings:
(?=.*one)(?=.*two)(?=.*three)
Below written code should do in case of one space char is there and your search string is in a variable called #a
...LIKE LEFT(#a,CHARINDEX(' ',#a)) AND ... LIKE RIGHT(#a,CHARINDEX(' ',#a))
Create another column in your table, say keywords, and when inserting data also create the keyword of your data by removing whitespace characters and insert to this column.
When searching search the keyword in this column.
create function createKeyword(#data nvarchar(256))
returns nvarchar(256)
as
begin
-- remove whitespace characters
return #kword
end
And when searching use
t.keywords like '%' + dbo.createKeyword(#data) + '%'