Reputation: 22559
I have three TVP - A, B and C
A is never empty. B or C can be empty.
AND
SomeId IN (SELECT n FROM @A) -- First
AND
SomeId IN (SELECT n FROM @B) -- Second -- Make this optional
AND
SomeId IN (SELECT n FROM @C) -- Third -- Make this optional
I need to make the Second/Third condition optional. I have tried quite a lot of things like case, (SELECT .. OR @B = null)
, but since these are table value parameters its not working.
Upvotes: 0
Views: 891
Reputation: 833
It would be much cleaner and equally as succinct to do the following:
;WITH AllowedIds_CTE (SomeId) AS (
SELECT n from @A
UNION
SELECT n from @B
UNION
SELECT n from @C
)
SELECT * FROM SomeTable O
JOIN AllowedIds_CTE A
ON O.SomeId = A.SomeId;
Multiple nested subqueries and IN
operations are less readable and potentially less efficient than joins with CTEs/tables.
The CTE (Common Table Expression) in this model can be replaced with an indexed temp table if performance is a concern, and UNION
can be replaced with UNION ALL
if you know your n
values to be distinct across @A
, @B
and @C
.
Upvotes: 1
Reputation: 48776
Try the following. It starts off as the same query as the original, but for each of the two "optional" TVPs it adds a UNION ALL to select the "SomeId" ONLY IF there are now rows in that particular TVP. This keeps with the intent of using the TVP as a filter IF there are rows in it, else it does not filter out the row.
DECLARE @Main TABLE (ID INT);
INSERT INTO @Main (ID) VALUES (55);
INSERT INTO @Main (ID) VALUES (999);
DECLARE @TestA TABLE (Col1 INT);
INSERT INTO @TestA (Col1) VALUES (55);
INSERT INTO @TestA (Col1) VALUES (67855);
DECLARE @TestB TABLE (Col1 INT);
--INSERT INTO @TestB (Col1) VALUES (565);
SELECT tmp.ID
FROM @Main tmp
WHERE tmp.ID IN (SELECT Col1 FROM @TestA)
AND tmp.ID IN (
SELECT Col1 FROM @TestB
UNION ALL
SELECT tmp.ID
WHERE NOT EXISTS(SELECT * FROM @TestB)
)
The query (with the INSERT INTO @TestB
commented out) returns the value of 55
since @TestB is "optional". But if you uncomment that INSERT INTO @TestB
, then nothing is returned since @TestB does not contain the value 55
.
Upvotes: 1
Reputation: 1932
SELECT m.*, a.N, b.N, c.N FROM MyTable m
INNER JOIN @A a
ON a.N = m.SomeId
LEFT JOIN @B b
ON b.N = m.SomeId
LEFT JOIN @C c
ON c.N = m.SomeId
So you are trying to get all the records that match to a, and then if they match to b or c, then you can do something with them?
Upvotes: 1
Reputation: 360
I have seen and set stored procedures where the parameters are defaulted to NULL
@A int = NULL,
@B int = NULL,
@C int = NULL
The code behind will load in parameters, and @B and @C may or may not be loaded.
When you get to your WHERE
clause, you put
SomeId IN (SELECT n FROM @A)
AND (SomeID IN (SELECT n FROM @B) OR @B IS NULL)
AND (SomeID IN (SELECT n FROM @C) OR @C IS NULL)
Notice the syntax; it is not @B = NULL
, it is @B IS NULL
Upvotes: 1
Reputation: 48018
If only the second and third conditions are optional, then try this
AND SomeId IN (SELECT n FROM @A) -- First
OR
(
SomeId IN (SELECT n FROM @B) -- Second -- Make this optional
OR
SomeId IN (SELECT n FROM @C) -- Third -- Make this optional
)
Upvotes: 1
Reputation: 3844
Try using OR
AND
(
SomeId IN (SELECT n FROM @A) -- First
OR
SomeId IN (SELECT n FROM @B) -- Second -- Make this optional
OR
SomeId IN (SELECT n FROM @C) -- Third -- Make this optional
)
Upvotes: 1