I am trying to match data in T-SQL from my tables as kindof an "IN with AND" clause. I can't think of how to describe this exactly other than with an example...
Here are my tables of data...
tbl_Values
| pkId | nv_Name | nv_Values |
|---|---|---|
| 1 | test1 | 1.1,2.1,3.1 |
| 2 | test2 | 1.2,2.1,3.1 |
| 3 | test3 | 1.1,2.2,3.1 |
tbl_MatchValues
| pkId | nv_MatchValue |
|---|---|
| 1 | 1.1 |
| 2 | 1.2 |
| 3 | 1.3 |
| 4 | 2.1 |
| 5 | 2.2 |
| 6 | 2.3 |
| 7 | 3.1 |
| 8 | 3.2 |
| 9 | 3.3 |
tbl_Values_MatchValues
| pkId | fk_ValueId | fk_MatchValueId |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 4 |
| 3 | 1 | 7 |
| 4 | 2 | 2 |
| 5 | 2 | 4 |
| 6 | 2 | 7 |
| 7 | 3 | 1 |
| 8 | 3 | 5 |
| 9 | 3 | 7 |
In the front-end I have a checkbox selector that allows the user to pick certain Values that are then passed to MSSQL in a CSV format, which populates the variable @CSV
-- CSV VALUES ARE FROM PICKLIST IN FRONT-END CODE
DECLARE @CSV AS VARCHAR(MAX) = '1.1,3.1'
-- CREATE TEMP TABLE TO HOLD CSV DATA
CREATE TABLE #TblValues (Number VARCHAR(MAX))
IF @CSV IS NOT NULL
INSERT INTO #TblValues
SELECT * FROM SplitString(@CSV,',')
SELECT val.[nv_Name]
,val.[nv_Values]
,mv.nv_MatchValue -- JUST FOR DEMONSTRATION
FROM [tbl_Values] AS val
JOIN [tbl_Values_MatchValues] AS vmv ON vmv.fk_ValueId = val.pkId
JOIN [tbl_MatchValues] AS mv ON vmv.fk_MatchValueId = mv.pkId
WHERE mv.nv_MatchValue IN (SELECT * FROM #TblValues)
The goal here is to get a list of all rows in tbl_Values that have ALL the Values listed in @CSV, but what I get is more of an OR so I get all the rows that have ANY of the Values listed, such as...
| nv_Name | nv_Values | nv_MatchValue |
|---|---|---|
| test1 | 1.1,2.1,3.1 | 1.1 |
| test1 | 1.1,2.1,3.1 | 3.1 |
| test2 | 1.2,2.1,3.1 | 3.1 |
| test3 | 1.1,2.2,3.1 | 1.1 |
| test3 | 1.1,2.2,3.1 | 3.1 |
And here, I would like to get test1 and test3 but NOT test2.
Any help is greatly appreciated...
[UPDATE]
I edited the query to read like this...
-- CSV VALUES ARE FROM PICKLIST IN FRONT-END CODE
DECLARE @CSV AS VARCHAR(MAX) = '1.1,3.1'
-- CREATE TEMP TABLE TO HOLD CSV DATA
CREATE TABLE #TblValues (Number VARCHAR(MAX))
IF @CSV IS NOT NULL
INSERT INTO #TblValues
SELECT * FROM SplitString(@CSV,',')
SELECT val.[nv_Name]
,val.[nv_Values]
--,mv.nv_MatchValue
FROM [tbl_Values] AS val
JOIN [tbl_Values_MatchValues] AS vmv ON vmv.fk_ValueId = val.pkId
JOIN [tbl_MatchValues] AS mv ON vmv.fk_MatchValueId = mv.pkId
WHERE mv.nv_MatchValue IN (SELECT * FROM #TblValues)
AND NOT EXISTS(
SELECT * FROM [tbl_MatchValues] t
LEFT JOIN #TblValues ON #TblValues.[Number] = t.nv_MatchValue
WHERE t.pkId = vmv.fk_MatchValueId
AND #TblValues.[Number] IS NULL)
And I am still getting test2 in my results...
[UPDATE]
Okay, I think I have it. At least I get the results I want, however it may not be very performant.
Here is the SQL...
-- CSV VALUES ARE FROM PICKLIST IN FRONT-END CODE
DECLARE @CSV AS VARCHAR(MAX) = '1,7'
-- CREATE TEMP TABLE TO HOLD CSV DATA
CREATE TABLE #TblValues (Number VARCHAR(MAX))
IF @CSV IS NOT NULL
INSERT INTO #TblValues
SELECT * FROM SplitString(@CSV,',')
SELECT
tvmv.fk_MatchValueId
,tmv.nv_MatchValue
,tvmv.fk_ValueId
,tv.nv_Name
,tv.nv_Values
INTO #TblCounts
FROM tbl_Values_MatchValues AS tvmv
JOIN tbl_MatchValues AS tmv ON tvmv.fk_MatchValueId = tmv.pkId
JOIN tbl_Values AS tv ON tvmv.fk_ValueId = tv.pkId
WHERE fk_MatchValueId IN (SELECT * FROM #TblValues)
SELECT
tc.nv_Name
,tc.nv_Values
,tc.nv_MatchValue
FROM #TblCounts AS tc
WHERE (SELECT COUNT(*) FROM #TblCounts AS tcinner WHERE tc.fk_ValueId = tcinner.fk_ValueId) = (SELECT COUNT(*) FROM #TblValues)
And here is the result... |nv_Name|nv_Values|nv_MatchValue| |-|-|-| |test1|1.1,2.1,3.1|1.1| |test1|1.1,2.1,3.1|3.1| |test3|1.1,2.2,3.1|1.1| |test3|1.1,2.2,3.1|3.1|
Is this bad practice or going to be slow at scale?