SQL breakup string for use with WHERE IN - sql

I have a table in SQL Server with a column that stores a series of characters. I would like to be able to send a series of characters to a stored procedure and use it for the WHERE IN. Example below
ID | series
---+-------
1 | U
2 | B
3 | R
4 | UB
5 | BR
I would like a return as follows:
Parameter | Return IDs
----------+------------
U | 1
R | 3
U, R | 1, 3
I can format the parameter any way, UR or U, R or whatever. I could break this up in application and call the procedure N times but I would rather not so that I can use an order by in the query.

Here's one way if you can not use a table valued parameter.
declare #table table (ID int, series varchar(16))
insert into #table
values
(1,'U'),
(2,'B'),
(3,'R'),
(4,'UB'),
(5,'BR')
declare #input varchar(4000) = 'U,R'
select
t.*
from #table t
cross apply dbo.DelimitedSplit8K(#input,',') x
where
x.Item = t.series
OR without Cross Apply
;with cte as
(select *
from dbo.DelimitedSplit8K(#input,',') x )
select
t.*
from #table t
inner join cte on Item = t.series
Here is the function which has proven to be a fast method of splitting strings:
CREATE FUNCTION [dbo].[DelimitedSplit8K] (#pString VARCHAR(8000), #pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
/* "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
enough to cover VARCHAR(8000)*/
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(#pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(#pString,t.N,1) = #pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(#pDelimiter,#pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(#pString, l.N1, l.L1)
FROM cteLen l
;
GO

On way to achieve this is to pass in a delimited string and then create a function to take in your parameter, splits out the values and returns a table value. Then all you need to do is create a stored procedure similar to.
CREATE PROCEDURE MyProc
(
#MyParameter NVARCHAR(3000)
)
AS
SELECT
ID,
Series
FROM
MyTable
WHERE
Series IN (SELECT ID FROM dbo.MyFunctionToSplitDelimitedString(#MyParameter,',')

Related

Substring instead of Left

All,
I have a query like this:
SELECT
[RecName],
CHARINDEX('_',[Rec Name]),
CASE
WHEN CHARINDEX('_',[Rec Name]) >=1 THEN
LEFT([Rec Name],CHARINDEX('_',[Rec Name])-1)
ELSE
'NA'
END RecTrimmed
FROM calculated_data
WHERE [Rec Name] = 'T101184_7AB_C1_ABCDE'
GROUP BY [Rec Name]
When I execute the above I get the following result - T101184
How can I achieve the same result using Substring?
Any lead would be appreciated.
Thanks,
John
One way is
with cte (col) as
(select 'T101184_7AB_C1_ABCDE' union all
select 'T1011847ABC1ABCDE')
select coalesce(nullif(substring(col,0,charindex('_',col)),''),'NA')
from cte;
Having said that, there is no reason you shouldn't use left for the problem you have at hand
One simple and quick solution could be to use an ordinal splitter to divide the string at '_' into rows. Then there's no need to fiddle around with LEFT and SUBSTRING and CHARINDEX.
The ordinal splitter can be found here
CREATE FUNCTION dbo.DelimitedSplit8K
--===== Define I/O parameters
(#pString VARCHAR(8000), #pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
-- enough to cover VARCHAR(8000)
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(#pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(#pString,t.N,1) = #pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(#pDelimiter,#pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(#pString, l.N1, l.L1)
FROM cteLen l
;
Then the query is very simple and executes efficiently
with cte (col) as (
select 'T101184_7AB_C1_ABCDE' union all
select 'T1011847ABC1ABCDE')
select Item
from cte c
cross apply
(select case when charindex('_',c.col)=0 then 'NA' else c.col end chr) ndx
cross apply
dbo.DelimitedSplit8K(ndx.chr, '_')
where ItemNumber=1;
Output
Item
T101184
NA

How to get values separated by comma into new record in SQL Server? [duplicate]

This question already has answers here:
Turning a Comma Separated string into individual rows
(16 answers)
Closed 5 years ago.
Could some one please explain how to get values separated by comma into a new record in SQL Server based on below mentioned scenario.
I have a table like this
Column 1 | Column 2
----------+--------------
abc | 12345
bcd | 13455,45678
sdf | 78934,13345
I want the result to be in the following way
Column1 | Column2
--------+----------
abc | 12345
bcd | 13455
bcd | 45678
sdf | 78934
sdf | 13345
Jason's answer would be my first choice (1+)
However, in case you can't use (or want) a TVF, here is an in-line approach.
Example
Select A.[Column 1]
,[Column 2] = B.RetVal
From YourTable A
Cross Apply (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B2.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace([Column 2],',','</x><x>')+'</x>' as xml).query('.')) B1
Cross Apply x.nodes('x') AS B2(i)
) B
Returns
Column 1 Column 2
abc 12345
bcd 13455
bcd 45678
sdf 78934
sdf 13345
Start with a good tally based string splitting function like Jeff Moden's DelimitedSplit8K
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
GO
CREATE FUNCTION [dbo].[DelimitedSplit8K]
--===== Define I/O parameters
(#pString VARCHAR(8000), #pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
-- enough to cover VARCHAR(8000)
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(#pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(#pString,t.N,1) = #pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(#pDelimiter,#pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(#pString, l.N1, l.L1)
FROM cteLen l
;
GO
Now your problem becomes a very simple matter...
IF OBJECT_ID('tempdb..#temp', 'U') IS NOT NULL
DROP TABLE #temp;
CREATE TABLE #temp (
Column1 CHAR(3),
Column2 VARCHAR(8000)
);
INSERT #temp (Column1,Column2) VALUES
('abc', '12345'),
('bcd', '13455,45678'),
('sdf', '78934,13345');
-- the actual query...
SELECT
t.Column1,
dsk.Item
FROM
#temp t
CROSS APPLY dbo.DelimitedSplit8K(t.Column2, ',') dsk;
Results...
Column1 Column2
------- --------
abc 12345
bcd 13455
bcd 45678
sdf 78934
sdf 13345
EDIT: The above makes the assumption that Column2 can have any number of elements in the CSV string. If the maximum number of elements is two, you can skip the splitter function and use something like the following...
SELECT
t.Column1,
v.Column2
FROM
#temp t
CROSS APPLY ( VALUES (NULLIF(CHARINDEX(',', t.Column2, 1), 0)) ) s (Split)
CROSS APPLY ( VALUES (1, LEFT(t.Column2, s.Split - 1)), (2, substring(t.Column2, ISNULL(s.Split, 0) + 1, 8000)) ) v (rn, Column2)
WHERE
v.Column2 IS NOT NULL
ORDER BY
v.rn;
You can use a Tally table based splitter like below:
select
column1,
split_values
from
(
select
t.column1,
SUBSTRING( t.column2, t1.N, ISNULL(NULLIF(CHARINDEX(',',t.column2,t1.N),0)-t1.N,8000)) as split_values
from #t t
join
(
select
t.column2,
1 as N
from #t t
UNION ALL
select
t.column2,
t1.N + 1 as N
from #t t
join
(
select
top 8000
row_number() over(order by (select NULL)) as N
from
sys.objects s1
cross join
sys.objects s2
) t1
on SUBSTRING(t.column2,t1.N,1) = ','
) t1
on t1.column2=t.column2
)a
order by column1
See live demo

Storing data in two CSV strings vs two db tables for fastest comparison

The scenario is that we have two lists:
A: 23,45,g5,33
B: 11,12,45,g9
We want the fastest mechanism in SQL SERVER to see if any of the values from B is available in A, in this example 45 is in A so it must return true.
The solution should describe the way to store the lists (CSV, tables etc.) and the comparison mechanism.
Each list is relatively small (average 10 values in each) but the comparison is being made many many times (very few writes, many many reads)
If you are stuck with the delimited string, consider the following:
Example:
Declare #YourTable Table ([ColA] varchar(50),[ColB] varchar(50))
Insert Into #YourTable Values
('23,45,g5,33' ,'11,12,45,g9')
,('no,match' ,'found,here')
Select *
from #YourTable A
Cross Apply (
Select Match=IsNull(sum(1),0)
From [dbo].[udf-Str-Parse-8K](ColA,',') B1
Join [dbo].[udf-Str-Parse-8K](ColB,',') B2 on B1.RetVal=B2.RetVal
) B
Returns
ColA ColB Match
23,45,g5,33 11,12,45,g9 1
no,match found,here 0
The UDF if Interested
CREATE FUNCTION [dbo].[udf-Str-Parse-8K] (#String varchar(max),#Delimiter varchar(25))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(#String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(#Delimiter) From cte2 t Where Substring(#String,t.N,DataLength(#Delimiter)) = #Delimiter),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(#Delimiter,#String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By A.N)
,RetVal = LTrim(RTrim(Substring(#String, A.N, A.L)))
From cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
I'm still confused as to the core idea... but here is a simple solution that's better than a comma separated list. Creating indexes would make it faster, of course. It's far quicker than looping.
declare #table table (id char(4), v varchar(256))
insert into #table
values
('A','23'),
('A','45'),
('A','g5'),
('A','33'),
('B','11'),
('B','12'),
('B','45'),
('B','g9')
select distinct
base.v
--,base.*
--,compare.*
from
#table base
inner join
#table compare
on compare.v = base.v
and compare.id <> base.id
Split Way
declare #table table (id char(4), v varchar(256))
insert into #table
values
('A','23,45,g5,33'),
('B','11,12,45,g9')
;with cte as(
select
t.ID
,base.Item
from
#table t
cross apply dbo.DelimitedSplit8K(t.v,',') base)
select
t.Item
from
cte t
inner join
cte x on
x.Item = t.Item
and x.id <> t.id
where
t.id = 'A'
USING THIS FUNCTION
CREATE FUNCTION [dbo].[DelimitedSplit8K] (#pString VARCHAR(8000), #pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
/* "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
enough to cover VARCHAR(8000)*/
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(#pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(#pString,t.N,1) = #pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(#pDelimiter,#pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(#pString, l.N1, l.L1)
FROM cteLen l
;
GO
Based on the previous answer, I think it should look like this:
declare #table table (id char(4), v varchar(256))
insert into #table
values
('A','23'),
('A','45'),
('A','g5'),
('A','33'),
('B','11'),
('B','12'),
('B','45'),
('B','g9')
if exists( select count(1)
from
#table base
inner join
#table compare
on compare.v = base.v
and base.id='A' and compare.id='B')
print 'true'
else
print 'false'
index on id, v or v, id depending on grow of your data

i have string as 'abc,def,ghi,jkl' [duplicate]

This question already has answers here:
SQL Server split CSV into multiple rows
(4 answers)
Closed 6 years ago.
i want to string in table column in new row as
table
abc
def
ghi
jkl
If you are using SQL SERVER 2016 then use STRING_SPLIT function
SELECT *
FROM String_split('abc,def,ghi,jkl', ',')
If you are using anything less than SQL SREVER 2016 then here is the best split string function. Referred from here
CREATE FUNCTION [dbo].[Delimitedsplit8k] (#pString VARCHAR(8000),
#pDelimiter CHAR(1))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000...
-- enough to cover NVARCHAR(4000)
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(#pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(#pString,t.N,1) = #pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(#pDelimiter,#pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(#pString, l.N1, l.L1)
FROM cteLen l
;
GO
To call the function
SELECT *
FROM dbo.DelimitedSplit8K('abc,def,ghi,jkl', ',')
You can use a Recursive CTE to split the string. It will allow you to track the position of the String within the string (if you want) and also provide a link back to your ID/Key value in your master table. (This allows you to avoid using a function if it's not an option)
CREATE TABLE #S(ID INT
,Qry VARCHAR(10)
)
INSERT INTO #S VALUES
(1,'TRA,B')
,(2,'X,YA,ZT')
DECLARE #s AS VARCHAR(1) = ','
;WITH cte_R
AS
(
SELECT
ID
,1 Ord
,LEFT(Qry,CHARINDEX(#s,Qry,0)) Val
,RIGHT(Qry,LEN(Qry)-CHARINDEX(#s,Qry,1)) Rem
FROM
#S
WHERE
Len(Qry) > 0
UNION ALL
SELECT
ID
,Ord+1
,LEFT(Rem,CHARINDEX(#s,Rem+#s,0))
,RIGHT(Rem,LEN(Rem)-CHARINDEX(#s,Rem,0))
FROM
cte_R
WHERE
CHARINDEX(#s,Val,0) > 0
)
SELECT
ID
,Ord
,REPLACE(Val,#s,'') Val
FROM
cte_R
ORDER BY
ID
,Ord

Getting several lines from a table in SQL Server and list them

I have a list with vehicles likes this:
Let's say I would like to display only cars with the ECUs TMS1 and C200. How do I do that?
I have inserted this function:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[SplitString]
(#pString NVARCHAR(4000), #pDelimiter NCHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(#pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(#pString,t.N,1) = #pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(#pDelimiter,#pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(#pString, l.N1, l.L1)
FROM cteLen l
WHERE SUBSTRING(#pString, l.N1, l.L1) <> ''
;
GO
and created this stored procedure:
Alter Procedure [db_ddladmin].[spGetVehicles]
(
#ECU nvarchar(20),
#Identifiers nvarchar(20)
)
AS
Begin
SELECT *
FROM db_ddladmin.View_VehicleReadouts
WHERE ECU IN (SELECT Item FROM [dbo].[SplitString](#ECU,',') )
AND Identifier IN (SELECT Item FROM [dbo].[SplitString](#Identifiers, ','))
END
And I execute this stored procedure by this query:
EXEC [db_ddladmin].[spGetVehicles] #ECU = 'EBS7,ALM1', #Identifiers = '88'
I get a list with all the vehicles containing those ECUs and Identifiers. But the thing is that I would only like to display vehicles that has both of the ECUs I have written there and not vehicles that has only one of those desired ECUs. How do I do that?
You can do this with aggregation and having. The idea is to count the number of matches:
with items(item) as (
select Item
from dbo.SplitString(#ECU, ',')
)
select ??
from db_ddladmin.View_VehicleReadouts
where ecu in (select items.item from items)
group by ??
having count(*) = (select count(*) from items);
The ?? represents the column that specifies the vehicle.
If there can be duplicates in the table, then use count(distinct ecu) rather than count(*) in the having clause.