Filter by using in for SQL Server
I have the below table
Col1 Col2
1 ACA,ABS,PHR
2 PHR
3 MCM
4 ABC
Now I want to filter the data from this so if I have a filter parameter as say 'ABS,MCM'
I want to get only the rows which have at least one matching code. So in this case I should get the filtered result as
Col1 Col2
1 ACA,ABS,PHR
2 MCM
Now I can use the query Select * from myTable where Col2 in ('ABS','MCM')
but then it won't retrieve the first row ACA,ABS,PHR
. Can some one please tell me how I can do a text search for codes so as long as one code matches in Col2 I get the row so I can pass in directly the , delimited list and as long as it finds a single match the row is retrieved.
Thanks
sql-server sql-server-2012
add a comment |
I have the below table
Col1 Col2
1 ACA,ABS,PHR
2 PHR
3 MCM
4 ABC
Now I want to filter the data from this so if I have a filter parameter as say 'ABS,MCM'
I want to get only the rows which have at least one matching code. So in this case I should get the filtered result as
Col1 Col2
1 ACA,ABS,PHR
2 MCM
Now I can use the query Select * from myTable where Col2 in ('ABS','MCM')
but then it won't retrieve the first row ACA,ABS,PHR
. Can some one please tell me how I can do a text search for codes so as long as one code matches in Col2 I get the row so I can pass in directly the , delimited list and as long as it finds a single match the row is retrieved.
Thanks
sql-server sql-server-2012
add a comment |
I have the below table
Col1 Col2
1 ACA,ABS,PHR
2 PHR
3 MCM
4 ABC
Now I want to filter the data from this so if I have a filter parameter as say 'ABS,MCM'
I want to get only the rows which have at least one matching code. So in this case I should get the filtered result as
Col1 Col2
1 ACA,ABS,PHR
2 MCM
Now I can use the query Select * from myTable where Col2 in ('ABS','MCM')
but then it won't retrieve the first row ACA,ABS,PHR
. Can some one please tell me how I can do a text search for codes so as long as one code matches in Col2 I get the row so I can pass in directly the , delimited list and as long as it finds a single match the row is retrieved.
Thanks
sql-server sql-server-2012
I have the below table
Col1 Col2
1 ACA,ABS,PHR
2 PHR
3 MCM
4 ABC
Now I want to filter the data from this so if I have a filter parameter as say 'ABS,MCM'
I want to get only the rows which have at least one matching code. So in this case I should get the filtered result as
Col1 Col2
1 ACA,ABS,PHR
2 MCM
Now I can use the query Select * from myTable where Col2 in ('ABS','MCM')
but then it won't retrieve the first row ACA,ABS,PHR
. Can some one please tell me how I can do a text search for codes so as long as one code matches in Col2 I get the row so I can pass in directly the , delimited list and as long as it finds a single match the row is retrieved.
Thanks
sql-server sql-server-2012
sql-server sql-server-2012
asked Feb 14 at 19:05
user1221989user1221989
1444
1444
add a comment |
add a comment |
5 Answers
5
active
oldest
votes
You could also split the string and then search on the splitted values.
An example could be by creating and using this function.
Starting from SQL Server 2016 you could use the built in STRING_SPLIT()
function.
Creating the function from the blogpost and executing this query afterwards
SELECT DISTINCT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.fnSplitString(col2,',')
WHERE splitdata in ('ABS','MCM');
Result
Col1 Col2
1 ACA,ABS,PHR
3 MCM
DB<>Fiddle
An optimization could be proactively splitting the table into a permanent one so you don't need to do splitting on the entire table everytime. (If the values are static)
EDIT
Comment by @Erikdarling
There are better ways to split strings: Comparing string splitting /
concatenation methods, including a much better one at SSC by Jeff
Moden.
The function by Jeff Moden
After creating the function in his blogpost, you could use a query that resembles the previous one.
SELECT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.DelimitedSplit8k(Col2,',') split
WHERE split.Item in ('ABS','MCM');
DB<>Fiddle
add a comment |
When I see filter parameter, I think input parameter to a stored procedure, so nothing hardcoded in the actual query. This is a twist on @Randi's version that uses an inline string splitter technique to split the incoming parameter into rows and using CROSS APPLY
and LIKE
to find matches.
--demo setup
declare @T table(col1 int, col2 varchar(100))
insert into @T(col1,col2) values
(1,'ACA,ABS,PHR'),
(2,'PHR'),
(3,'MCM'),
(4,'ABC')
--Declare the input parameter - passed into a stored procedure perhaps?
Declare @Parm varchar(100) = 'ABS,MCM'
--Common Table Expression - Inline string splitter, since you can't use STRING_SPLIT() from SQL 2016
;WITH SplitParms
AS (
SELECT LTRIM(RTRIM(m.n.value('.[1]', 'varchar(8000)'))) AS Code
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(@Parm, ',', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
) t
CROSS APPLY x.nodes('/XMLRoot/RowData') m(n)
)
--use CROSS APPLY and LIKE to find matching rows
SELECT t.*
FROM @t t
CROSS APPLY SplitParms sp
WHERE t.col2 LIKE ('%' + sp.Code + '%')
| col1 | col2 |
|------|-------------|
| 1 | ACA,ABS,PHR |
| 3 | MCM |
add a comment |
You would need to use like.
where col2 like '%ABS%' or col2 like '%MCM%'
1
Agreed that this will work, but I cannot help but feel that there must be an easier/more dynamic way of doing this.
– WadeH
Feb 14 at 19:30
@WadeH It depends on the codes. It will fail ifLABST
is also a code.
– jpmc26
Feb 15 at 0:44
add a comment |
Here is another solution. I don't have a large enough dataset to show performance gains either way, but one option (my Attempt 1) splits the string you are searching rather than the entire table. Of course, unbound string searches may be more costly than you want to pay, but you can do testing to show. Alternatively, in Attempt 3, I show how you can do it without using a string of OR clauses or string_split.
/** BUILD UP DATA */
DECLARE @SearchString VARCHAR(100) = 'ABS,MCM'
DECLARE @Test TABLE
(
Col1 INT NOT NULL PRIMARY KEY IDENTITY(1,1)
, Col2 VARCHAR(100) NULL
)
INSERT INTO @Test
(Col2)
VALUES ('ACA,ABS PHR')
, ('PHR')
, ('MCM')
, ('ABC')
, ('ABS,MCM') --Included to demonstrate if one record has multiple code matches.
/** ATTEMPT 1 - UNBOUNDED WILDCARD SEARCH
- Still uses STRING_SPLIT, just on the Search String rather than the main table.
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(@SearchString, ',') AS V
WHERE T.Col2 LIKE '%' + LTRIM(RTRIM(V.value)) + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 2 - DIRECT QUERY,
but uses STRING_SPLIT on the Col2
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(T.Col2, ',') AS V
WHERE V.value IN ('ABS', 'MCM')
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 3 - UNBOUND WILDCARD, but no string splitting required.
*/
DECLARE @SearchTable TABLE
(
Code VARCHAR(3) NOT NULL
)
INSERT INTO @SearchTable
(Code)
VALUES ('ABS')
, ('MCM')
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
INNER JOIN @SearchTable AS P ON T.Col2 LIKE '%' + P.Code + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
add a comment |
The most correct solution is to normalize. You need to put the codes in another table with a foreign key:
CREATE TABLE MyThings (
Col1 IDENTITY PRIMARY KEY,
-- Other columns you already have on the table
Col3 VARCHAR(200) NOT NULL,
Col4 DECIMAL NOT NULL
);
-- Probably needs some kind of primary key.
CREATE TABLE MyThingCodes (
Col1 NOT NULL REFERENCES MyThings (Col1),
Code VARCHAR(30) NOT NULL
);
And we can index it (since the codes are short) to speed up these queries:
CREATE INDEX idx_MyThingCodes_Code ON MyThingCodes (Code);
Then you can use an EXISTS
query to find rows that match the code:
SELECT *
FROM MyThings
WHERE EXISTS (
SELECT 1
FROM MyThingCodes
WHERE
MyThingCodes.Col1 = MyThings.Col1
AND MyThingCodes.Code IN ('ABS','MCM')
)
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "182"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f229784%2ffilter-by-using-in-for-sql-server%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
You could also split the string and then search on the splitted values.
An example could be by creating and using this function.
Starting from SQL Server 2016 you could use the built in STRING_SPLIT()
function.
Creating the function from the blogpost and executing this query afterwards
SELECT DISTINCT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.fnSplitString(col2,',')
WHERE splitdata in ('ABS','MCM');
Result
Col1 Col2
1 ACA,ABS,PHR
3 MCM
DB<>Fiddle
An optimization could be proactively splitting the table into a permanent one so you don't need to do splitting on the entire table everytime. (If the values are static)
EDIT
Comment by @Erikdarling
There are better ways to split strings: Comparing string splitting /
concatenation methods, including a much better one at SSC by Jeff
Moden.
The function by Jeff Moden
After creating the function in his blogpost, you could use a query that resembles the previous one.
SELECT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.DelimitedSplit8k(Col2,',') split
WHERE split.Item in ('ABS','MCM');
DB<>Fiddle
add a comment |
You could also split the string and then search on the splitted values.
An example could be by creating and using this function.
Starting from SQL Server 2016 you could use the built in STRING_SPLIT()
function.
Creating the function from the blogpost and executing this query afterwards
SELECT DISTINCT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.fnSplitString(col2,',')
WHERE splitdata in ('ABS','MCM');
Result
Col1 Col2
1 ACA,ABS,PHR
3 MCM
DB<>Fiddle
An optimization could be proactively splitting the table into a permanent one so you don't need to do splitting on the entire table everytime. (If the values are static)
EDIT
Comment by @Erikdarling
There are better ways to split strings: Comparing string splitting /
concatenation methods, including a much better one at SSC by Jeff
Moden.
The function by Jeff Moden
After creating the function in his blogpost, you could use a query that resembles the previous one.
SELECT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.DelimitedSplit8k(Col2,',') split
WHERE split.Item in ('ABS','MCM');
DB<>Fiddle
add a comment |
You could also split the string and then search on the splitted values.
An example could be by creating and using this function.
Starting from SQL Server 2016 you could use the built in STRING_SPLIT()
function.
Creating the function from the blogpost and executing this query afterwards
SELECT DISTINCT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.fnSplitString(col2,',')
WHERE splitdata in ('ABS','MCM');
Result
Col1 Col2
1 ACA,ABS,PHR
3 MCM
DB<>Fiddle
An optimization could be proactively splitting the table into a permanent one so you don't need to do splitting on the entire table everytime. (If the values are static)
EDIT
Comment by @Erikdarling
There are better ways to split strings: Comparing string splitting /
concatenation methods, including a much better one at SSC by Jeff
Moden.
The function by Jeff Moden
After creating the function in his blogpost, you could use a query that resembles the previous one.
SELECT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.DelimitedSplit8k(Col2,',') split
WHERE split.Item in ('ABS','MCM');
DB<>Fiddle
You could also split the string and then search on the splitted values.
An example could be by creating and using this function.
Starting from SQL Server 2016 you could use the built in STRING_SPLIT()
function.
Creating the function from the blogpost and executing this query afterwards
SELECT DISTINCT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.fnSplitString(col2,',')
WHERE splitdata in ('ABS','MCM');
Result
Col1 Col2
1 ACA,ABS,PHR
3 MCM
DB<>Fiddle
An optimization could be proactively splitting the table into a permanent one so you don't need to do splitting on the entire table everytime. (If the values are static)
EDIT
Comment by @Erikdarling
There are better ways to split strings: Comparing string splitting /
concatenation methods, including a much better one at SSC by Jeff
Moden.
The function by Jeff Moden
After creating the function in his blogpost, you could use a query that resembles the previous one.
SELECT Col1,Col2
FROM dbo.Searching
CROSS APPLY dbo.DelimitedSplit8k(Col2,',') split
WHERE split.Item in ('ABS','MCM');
DB<>Fiddle
edited Feb 14 at 20:18
answered Feb 14 at 19:31
Randi VertongenRandi Vertongen
2,876721
2,876721
add a comment |
add a comment |
When I see filter parameter, I think input parameter to a stored procedure, so nothing hardcoded in the actual query. This is a twist on @Randi's version that uses an inline string splitter technique to split the incoming parameter into rows and using CROSS APPLY
and LIKE
to find matches.
--demo setup
declare @T table(col1 int, col2 varchar(100))
insert into @T(col1,col2) values
(1,'ACA,ABS,PHR'),
(2,'PHR'),
(3,'MCM'),
(4,'ABC')
--Declare the input parameter - passed into a stored procedure perhaps?
Declare @Parm varchar(100) = 'ABS,MCM'
--Common Table Expression - Inline string splitter, since you can't use STRING_SPLIT() from SQL 2016
;WITH SplitParms
AS (
SELECT LTRIM(RTRIM(m.n.value('.[1]', 'varchar(8000)'))) AS Code
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(@Parm, ',', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
) t
CROSS APPLY x.nodes('/XMLRoot/RowData') m(n)
)
--use CROSS APPLY and LIKE to find matching rows
SELECT t.*
FROM @t t
CROSS APPLY SplitParms sp
WHERE t.col2 LIKE ('%' + sp.Code + '%')
| col1 | col2 |
|------|-------------|
| 1 | ACA,ABS,PHR |
| 3 | MCM |
add a comment |
When I see filter parameter, I think input parameter to a stored procedure, so nothing hardcoded in the actual query. This is a twist on @Randi's version that uses an inline string splitter technique to split the incoming parameter into rows and using CROSS APPLY
and LIKE
to find matches.
--demo setup
declare @T table(col1 int, col2 varchar(100))
insert into @T(col1,col2) values
(1,'ACA,ABS,PHR'),
(2,'PHR'),
(3,'MCM'),
(4,'ABC')
--Declare the input parameter - passed into a stored procedure perhaps?
Declare @Parm varchar(100) = 'ABS,MCM'
--Common Table Expression - Inline string splitter, since you can't use STRING_SPLIT() from SQL 2016
;WITH SplitParms
AS (
SELECT LTRIM(RTRIM(m.n.value('.[1]', 'varchar(8000)'))) AS Code
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(@Parm, ',', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
) t
CROSS APPLY x.nodes('/XMLRoot/RowData') m(n)
)
--use CROSS APPLY and LIKE to find matching rows
SELECT t.*
FROM @t t
CROSS APPLY SplitParms sp
WHERE t.col2 LIKE ('%' + sp.Code + '%')
| col1 | col2 |
|------|-------------|
| 1 | ACA,ABS,PHR |
| 3 | MCM |
add a comment |
When I see filter parameter, I think input parameter to a stored procedure, so nothing hardcoded in the actual query. This is a twist on @Randi's version that uses an inline string splitter technique to split the incoming parameter into rows and using CROSS APPLY
and LIKE
to find matches.
--demo setup
declare @T table(col1 int, col2 varchar(100))
insert into @T(col1,col2) values
(1,'ACA,ABS,PHR'),
(2,'PHR'),
(3,'MCM'),
(4,'ABC')
--Declare the input parameter - passed into a stored procedure perhaps?
Declare @Parm varchar(100) = 'ABS,MCM'
--Common Table Expression - Inline string splitter, since you can't use STRING_SPLIT() from SQL 2016
;WITH SplitParms
AS (
SELECT LTRIM(RTRIM(m.n.value('.[1]', 'varchar(8000)'))) AS Code
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(@Parm, ',', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
) t
CROSS APPLY x.nodes('/XMLRoot/RowData') m(n)
)
--use CROSS APPLY and LIKE to find matching rows
SELECT t.*
FROM @t t
CROSS APPLY SplitParms sp
WHERE t.col2 LIKE ('%' + sp.Code + '%')
| col1 | col2 |
|------|-------------|
| 1 | ACA,ABS,PHR |
| 3 | MCM |
When I see filter parameter, I think input parameter to a stored procedure, so nothing hardcoded in the actual query. This is a twist on @Randi's version that uses an inline string splitter technique to split the incoming parameter into rows and using CROSS APPLY
and LIKE
to find matches.
--demo setup
declare @T table(col1 int, col2 varchar(100))
insert into @T(col1,col2) values
(1,'ACA,ABS,PHR'),
(2,'PHR'),
(3,'MCM'),
(4,'ABC')
--Declare the input parameter - passed into a stored procedure perhaps?
Declare @Parm varchar(100) = 'ABS,MCM'
--Common Table Expression - Inline string splitter, since you can't use STRING_SPLIT() from SQL 2016
;WITH SplitParms
AS (
SELECT LTRIM(RTRIM(m.n.value('.[1]', 'varchar(8000)'))) AS Code
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(@Parm, ',', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
) t
CROSS APPLY x.nodes('/XMLRoot/RowData') m(n)
)
--use CROSS APPLY and LIKE to find matching rows
SELECT t.*
FROM @t t
CROSS APPLY SplitParms sp
WHERE t.col2 LIKE ('%' + sp.Code + '%')
| col1 | col2 |
|------|-------------|
| 1 | ACA,ABS,PHR |
| 3 | MCM |
answered Feb 14 at 20:04
Scott HodginScott Hodgin
17.4k21534
17.4k21534
add a comment |
add a comment |
You would need to use like.
where col2 like '%ABS%' or col2 like '%MCM%'
1
Agreed that this will work, but I cannot help but feel that there must be an easier/more dynamic way of doing this.
– WadeH
Feb 14 at 19:30
@WadeH It depends on the codes. It will fail ifLABST
is also a code.
– jpmc26
Feb 15 at 0:44
add a comment |
You would need to use like.
where col2 like '%ABS%' or col2 like '%MCM%'
1
Agreed that this will work, but I cannot help but feel that there must be an easier/more dynamic way of doing this.
– WadeH
Feb 14 at 19:30
@WadeH It depends on the codes. It will fail ifLABST
is also a code.
– jpmc26
Feb 15 at 0:44
add a comment |
You would need to use like.
where col2 like '%ABS%' or col2 like '%MCM%'
You would need to use like.
where col2 like '%ABS%' or col2 like '%MCM%'
edited Feb 14 at 19:51
Randi Vertongen
2,876721
2,876721
answered Feb 14 at 19:13
JoeDBA_HAHAHAJoeDBA_HAHAHA
191
191
1
Agreed that this will work, but I cannot help but feel that there must be an easier/more dynamic way of doing this.
– WadeH
Feb 14 at 19:30
@WadeH It depends on the codes. It will fail ifLABST
is also a code.
– jpmc26
Feb 15 at 0:44
add a comment |
1
Agreed that this will work, but I cannot help but feel that there must be an easier/more dynamic way of doing this.
– WadeH
Feb 14 at 19:30
@WadeH It depends on the codes. It will fail ifLABST
is also a code.
– jpmc26
Feb 15 at 0:44
1
1
Agreed that this will work, but I cannot help but feel that there must be an easier/more dynamic way of doing this.
– WadeH
Feb 14 at 19:30
Agreed that this will work, but I cannot help but feel that there must be an easier/more dynamic way of doing this.
– WadeH
Feb 14 at 19:30
@WadeH It depends on the codes. It will fail if
LABST
is also a code.– jpmc26
Feb 15 at 0:44
@WadeH It depends on the codes. It will fail if
LABST
is also a code.– jpmc26
Feb 15 at 0:44
add a comment |
Here is another solution. I don't have a large enough dataset to show performance gains either way, but one option (my Attempt 1) splits the string you are searching rather than the entire table. Of course, unbound string searches may be more costly than you want to pay, but you can do testing to show. Alternatively, in Attempt 3, I show how you can do it without using a string of OR clauses or string_split.
/** BUILD UP DATA */
DECLARE @SearchString VARCHAR(100) = 'ABS,MCM'
DECLARE @Test TABLE
(
Col1 INT NOT NULL PRIMARY KEY IDENTITY(1,1)
, Col2 VARCHAR(100) NULL
)
INSERT INTO @Test
(Col2)
VALUES ('ACA,ABS PHR')
, ('PHR')
, ('MCM')
, ('ABC')
, ('ABS,MCM') --Included to demonstrate if one record has multiple code matches.
/** ATTEMPT 1 - UNBOUNDED WILDCARD SEARCH
- Still uses STRING_SPLIT, just on the Search String rather than the main table.
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(@SearchString, ',') AS V
WHERE T.Col2 LIKE '%' + LTRIM(RTRIM(V.value)) + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 2 - DIRECT QUERY,
but uses STRING_SPLIT on the Col2
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(T.Col2, ',') AS V
WHERE V.value IN ('ABS', 'MCM')
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 3 - UNBOUND WILDCARD, but no string splitting required.
*/
DECLARE @SearchTable TABLE
(
Code VARCHAR(3) NOT NULL
)
INSERT INTO @SearchTable
(Code)
VALUES ('ABS')
, ('MCM')
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
INNER JOIN @SearchTable AS P ON T.Col2 LIKE '%' + P.Code + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
add a comment |
Here is another solution. I don't have a large enough dataset to show performance gains either way, but one option (my Attempt 1) splits the string you are searching rather than the entire table. Of course, unbound string searches may be more costly than you want to pay, but you can do testing to show. Alternatively, in Attempt 3, I show how you can do it without using a string of OR clauses or string_split.
/** BUILD UP DATA */
DECLARE @SearchString VARCHAR(100) = 'ABS,MCM'
DECLARE @Test TABLE
(
Col1 INT NOT NULL PRIMARY KEY IDENTITY(1,1)
, Col2 VARCHAR(100) NULL
)
INSERT INTO @Test
(Col2)
VALUES ('ACA,ABS PHR')
, ('PHR')
, ('MCM')
, ('ABC')
, ('ABS,MCM') --Included to demonstrate if one record has multiple code matches.
/** ATTEMPT 1 - UNBOUNDED WILDCARD SEARCH
- Still uses STRING_SPLIT, just on the Search String rather than the main table.
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(@SearchString, ',') AS V
WHERE T.Col2 LIKE '%' + LTRIM(RTRIM(V.value)) + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 2 - DIRECT QUERY,
but uses STRING_SPLIT on the Col2
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(T.Col2, ',') AS V
WHERE V.value IN ('ABS', 'MCM')
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 3 - UNBOUND WILDCARD, but no string splitting required.
*/
DECLARE @SearchTable TABLE
(
Code VARCHAR(3) NOT NULL
)
INSERT INTO @SearchTable
(Code)
VALUES ('ABS')
, ('MCM')
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
INNER JOIN @SearchTable AS P ON T.Col2 LIKE '%' + P.Code + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
add a comment |
Here is another solution. I don't have a large enough dataset to show performance gains either way, but one option (my Attempt 1) splits the string you are searching rather than the entire table. Of course, unbound string searches may be more costly than you want to pay, but you can do testing to show. Alternatively, in Attempt 3, I show how you can do it without using a string of OR clauses or string_split.
/** BUILD UP DATA */
DECLARE @SearchString VARCHAR(100) = 'ABS,MCM'
DECLARE @Test TABLE
(
Col1 INT NOT NULL PRIMARY KEY IDENTITY(1,1)
, Col2 VARCHAR(100) NULL
)
INSERT INTO @Test
(Col2)
VALUES ('ACA,ABS PHR')
, ('PHR')
, ('MCM')
, ('ABC')
, ('ABS,MCM') --Included to demonstrate if one record has multiple code matches.
/** ATTEMPT 1 - UNBOUNDED WILDCARD SEARCH
- Still uses STRING_SPLIT, just on the Search String rather than the main table.
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(@SearchString, ',') AS V
WHERE T.Col2 LIKE '%' + LTRIM(RTRIM(V.value)) + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 2 - DIRECT QUERY,
but uses STRING_SPLIT on the Col2
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(T.Col2, ',') AS V
WHERE V.value IN ('ABS', 'MCM')
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 3 - UNBOUND WILDCARD, but no string splitting required.
*/
DECLARE @SearchTable TABLE
(
Code VARCHAR(3) NOT NULL
)
INSERT INTO @SearchTable
(Code)
VALUES ('ABS')
, ('MCM')
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
INNER JOIN @SearchTable AS P ON T.Col2 LIKE '%' + P.Code + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
Here is another solution. I don't have a large enough dataset to show performance gains either way, but one option (my Attempt 1) splits the string you are searching rather than the entire table. Of course, unbound string searches may be more costly than you want to pay, but you can do testing to show. Alternatively, in Attempt 3, I show how you can do it without using a string of OR clauses or string_split.
/** BUILD UP DATA */
DECLARE @SearchString VARCHAR(100) = 'ABS,MCM'
DECLARE @Test TABLE
(
Col1 INT NOT NULL PRIMARY KEY IDENTITY(1,1)
, Col2 VARCHAR(100) NULL
)
INSERT INTO @Test
(Col2)
VALUES ('ACA,ABS PHR')
, ('PHR')
, ('MCM')
, ('ABC')
, ('ABS,MCM') --Included to demonstrate if one record has multiple code matches.
/** ATTEMPT 1 - UNBOUNDED WILDCARD SEARCH
- Still uses STRING_SPLIT, just on the Search String rather than the main table.
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(@SearchString, ',') AS V
WHERE T.Col2 LIKE '%' + LTRIM(RTRIM(V.value)) + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 2 - DIRECT QUERY,
but uses STRING_SPLIT on the Col2
*/
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
CROSS APPLY STRING_SPLIT(T.Col2, ',') AS V
WHERE V.value IN ('ABS', 'MCM')
)
SELECT * FROM CTE_Distinct WHERE RN = 1
/** ATTEMPT 3 - UNBOUND WILDCARD, but no string splitting required.
*/
DECLARE @SearchTable TABLE
(
Code VARCHAR(3) NOT NULL
)
INSERT INTO @SearchTable
(Code)
VALUES ('ABS')
, ('MCM')
;WITH CTE_Distinct AS
(
SELECT T.*
, RN = ROW_NUMBER() OVER (PARTITION BY T.Col1 ORDER BY T.Col1)
FROM @Test AS T
INNER JOIN @SearchTable AS P ON T.Col2 LIKE '%' + P.Code + '%'
)
SELECT * FROM CTE_Distinct WHERE RN = 1
answered Feb 14 at 20:18
Jonathan FiteJonathan Fite
4,058818
4,058818
add a comment |
add a comment |
The most correct solution is to normalize. You need to put the codes in another table with a foreign key:
CREATE TABLE MyThings (
Col1 IDENTITY PRIMARY KEY,
-- Other columns you already have on the table
Col3 VARCHAR(200) NOT NULL,
Col4 DECIMAL NOT NULL
);
-- Probably needs some kind of primary key.
CREATE TABLE MyThingCodes (
Col1 NOT NULL REFERENCES MyThings (Col1),
Code VARCHAR(30) NOT NULL
);
And we can index it (since the codes are short) to speed up these queries:
CREATE INDEX idx_MyThingCodes_Code ON MyThingCodes (Code);
Then you can use an EXISTS
query to find rows that match the code:
SELECT *
FROM MyThings
WHERE EXISTS (
SELECT 1
FROM MyThingCodes
WHERE
MyThingCodes.Col1 = MyThings.Col1
AND MyThingCodes.Code IN ('ABS','MCM')
)
add a comment |
The most correct solution is to normalize. You need to put the codes in another table with a foreign key:
CREATE TABLE MyThings (
Col1 IDENTITY PRIMARY KEY,
-- Other columns you already have on the table
Col3 VARCHAR(200) NOT NULL,
Col4 DECIMAL NOT NULL
);
-- Probably needs some kind of primary key.
CREATE TABLE MyThingCodes (
Col1 NOT NULL REFERENCES MyThings (Col1),
Code VARCHAR(30) NOT NULL
);
And we can index it (since the codes are short) to speed up these queries:
CREATE INDEX idx_MyThingCodes_Code ON MyThingCodes (Code);
Then you can use an EXISTS
query to find rows that match the code:
SELECT *
FROM MyThings
WHERE EXISTS (
SELECT 1
FROM MyThingCodes
WHERE
MyThingCodes.Col1 = MyThings.Col1
AND MyThingCodes.Code IN ('ABS','MCM')
)
add a comment |
The most correct solution is to normalize. You need to put the codes in another table with a foreign key:
CREATE TABLE MyThings (
Col1 IDENTITY PRIMARY KEY,
-- Other columns you already have on the table
Col3 VARCHAR(200) NOT NULL,
Col4 DECIMAL NOT NULL
);
-- Probably needs some kind of primary key.
CREATE TABLE MyThingCodes (
Col1 NOT NULL REFERENCES MyThings (Col1),
Code VARCHAR(30) NOT NULL
);
And we can index it (since the codes are short) to speed up these queries:
CREATE INDEX idx_MyThingCodes_Code ON MyThingCodes (Code);
Then you can use an EXISTS
query to find rows that match the code:
SELECT *
FROM MyThings
WHERE EXISTS (
SELECT 1
FROM MyThingCodes
WHERE
MyThingCodes.Col1 = MyThings.Col1
AND MyThingCodes.Code IN ('ABS','MCM')
)
The most correct solution is to normalize. You need to put the codes in another table with a foreign key:
CREATE TABLE MyThings (
Col1 IDENTITY PRIMARY KEY,
-- Other columns you already have on the table
Col3 VARCHAR(200) NOT NULL,
Col4 DECIMAL NOT NULL
);
-- Probably needs some kind of primary key.
CREATE TABLE MyThingCodes (
Col1 NOT NULL REFERENCES MyThings (Col1),
Code VARCHAR(30) NOT NULL
);
And we can index it (since the codes are short) to speed up these queries:
CREATE INDEX idx_MyThingCodes_Code ON MyThingCodes (Code);
Then you can use an EXISTS
query to find rows that match the code:
SELECT *
FROM MyThings
WHERE EXISTS (
SELECT 1
FROM MyThingCodes
WHERE
MyThingCodes.Col1 = MyThings.Col1
AND MyThingCodes.Code IN ('ABS','MCM')
)
edited Feb 15 at 2:24
answered Feb 15 at 0:54
jpmc26jpmc26
8111126
8111126
add a comment |
add a comment |
Thanks for contributing an answer to Database Administrators Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f229784%2ffilter-by-using-in-for-sql-server%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown