Reputation: 13
I have a simple table with two fields -- an ID field (Primary Key, INT), and a PartNumber field (VARCHAR). What I'm trying to do is conditionally filter down to the part numbers that begin with either "C" or "E" if a specific expression is set to 1, otherwise show all rows. Is this possible? I've provided code below to better demonstrate my question:
/* Set up sample table */
DROP TABLE IF EXISTS #TestTbl
CREATE TABLE #TestTbl (ID INT PRIMARY KEY CLUSTERED,
PartNumber VARCHAR(100))
INSERT INTO #TestTbl (ID,
PartNumber)
SELECT t.ID,
t.PartNumber
FROM (VALUES (1, 'A11111'),
(2, 'A12341'),
(3, 'B12232'),
(4, 'C11111'),
(5, 'E99999'),
(6, 'A10101'),
(7, 'L99999'),
(8, 'T49390')) t(ID, PartNumber)
/* Make sure I can query it...and this also represents the results I want if the expression is not set to 1 */
SELECT t.*
FROM #TestTbl t
/* This query represents the effect of what I would like if the expression is set to 1 */
SELECT t.*
FROM #TestTbl t
WHERE t.PartNumber LIKE 'C%'
OR t.PartNumber LIKE 'E%'
/* This is my attempt to limit to PartNumbers that start with "C" or "E" in a way that requires me to change only one value.
This doesn't work. Instead 1 returns all rows and 0 returns no rows.*/
SELECT *
FROM #TestTbl t
CROSS APPLY (SELECT FilterFlag = IIF(t.PartNumber LIKE 'C%' OR t.PartNumber LIKE 'E%', 1, NULL)) ca
WHERE (CASE
WHEN ca.FilterFlag IS NOT NULL AND ca.FilterFlag = 1 THEN 1
WHEN ca.FilterFlag IS NULL THEN 1
ELSE 0
END) = 1 /* I would like to be able to toggle this "= 1" between 1 and 0.
1 would show only PartNumbers that start with "C" or "E" and 0 wouldn't apply the filter at all and therefore show all rows */
There may be another way to approach this but ideally this would be done in a single query and there would only be one value I would have to change to apply/not apply the filter (preferably at the end).
Thanks in advance!
Upvotes: 0
Views: 133
Reputation: 555
You can solve this using a nested IIF
function in the where
clause:
declare @flag int =1
;with your_data as (
SELECT t.ID,
t.PartNumber
FROM (VALUES (1, 'A11111'),
(2, 'A12341'),
(3, 'B12232'),
(4, 'C11111'),
(5, 'E99999'),
(6, 'A10101'),
(7, 'L99999'),
(8, 'T49390')) t(ID, PartNumber)
)select * from your_data
where iif(@flag=1 and (partnumber like 'c%' or partnumber like 'e%'), partnumber, iif(@flag <>1, partnumber, ''))=partnumber;
Upvotes: 0
Reputation: 9272
This can be solved by creating two sets of data, where one set is all and other is the filtered one.
SELECT *
FROM #TestTbl t
CROSS APPLY (
SELECT t.*, 0 AS FilterFlag
UNION ALL
SELECT t.*, 1
WHERE t.PartNumber LIKE 'C%' OR t.PartNumber LIKE 'E%'
) x
WHERE x.FilterFlag = 1 -- or 0
This works but looks a bit "weird" in my eyes. Usually, for such filters, it's more easier to just do:
SELECT *
FROM #TestTbl t
WHERE (t.PartNumber LIKE 'C%' OR t.PartNumber LIKE 'E%') OR @someParameter IS NULL
Since you often use a parameter to create your filter condition.
Upvotes: 1
Reputation: 27388
You overcomplicated it - you don't need a CASE expression, just simple AND/OR logic.
Also returning a FilterFlag of null just added to the complexity.
DECLARE @ToggleFlag bit = 1;
SELECT *
FROM #TestTbl t
CROSS APPLY (SELECT FilterFlag = IIF(t.PartNumber LIKE 'C%' OR t.PartNumber LIKE 'E%', 1, 0)) ca
WHERE @ToggleFlag = 0 OR ca.FilterFlag = 1;
You don't even need the CROSS APPLY
SELECT *
FROM #TestTbl t
WHERE @ToggleFlag = 0 OR t.PartNumber LIKE 'C%' OR t.PartNumber LIKE 'E%';
Note: @ToggleFlag = 0
can be replaced by any expression you desire - it doesn't need to be a variable.
Upvotes: 2