Использование case вместо IF ELSE для изменения предложения WHERE в SQL
Я пытаюсь построить запрос, в котором предложение where немного меняется в зависимости от внешней переменной, и я придумал скрипт ниже
IF(@threshold='N')
select min_price
, s.customization_type
, gii.brand
, gii.item_flag
from item_info gii
, style s
, categories gpc
where isnull(@ordered,getdate()) between gpc.start_date and isnull(gpc.end_date, dateadd(day, 1, getdate()))
and gii.segment1 = s.style_number
and gpc.line_of_business_category = 'AAA'
and gii.inventory_item_id = @v_item_id;
ELSE
select min_price
, s.customization_type
, gii.brand
, gii.item_flag
from item_info gii
, style s
, categories gpc
where isnull(@ordered,getdate()) between gpc.start_date and isnull(gpc.end_date, dateadd(day, 1, getdate()))
and gii.segment1 = s.style_number
and gpc.line_of_business_category = 'BBB'
and gii.inventory_item_id = @v_item_id;
Но я чувствую, что приведенный выше запрос не является чистым, хотя и дает желаемые результаты. Есть ли лучший способ оптимизировать этот запрос, например, используя CASE WHEN?
6 ответов
Насколько я вижу, вам нужно только изменить эту строку:
gpc.line_of_business_category = 'AAA'
в
gpc.line_of_business_category = CASE
WHEN @threshold='N' THEN 'AAA'
ELSE 'BBB'
END
Если вы используете SQL Server 2012 или новее, то IIF
другая альтернатива:
gpc.line_of_business_category = IIF(@threshold='N', 'AAA', 'BBB')
Вы можете использовать как ниже:
where gpc.line_of_business = case when @threshold='N' then 'AAA' else 'BBB' end
select min_price
, s.customization_type
, gii.brand
, gii.item_flag
from item_info gii
, style s
, categories gpc
where isnull(@ordered,getdate()) between gpc.start_date and isnull(gpc.end_date, dateadd(day, 1, getdate()))
and gii.segment1 = s.style_number
and gii.inventory_item_id = @v_item_id;
and gpc.line_of_business_category = (CASE WHEN @threshold='N' THEN 'AAA' ELSE 'BBB' END)
Но вы должны использовать явный синтаксис соединения!
При использовании синтаксиса явного соединения это делает ваши намерения более понятными для других при отладке кода:
select
min_price
,s.customization_type
,gii.brand
,gii.item_flag
from
item_info gii
INNER JOIN style s
ON gii.segment1 = s.style_number
INNER JOIN categories gpc
ON isnull(@ordered,getdate()) between gpc.start_date and isnull(gpc.end_date, dateadd(day, 1, getdate()))
and gpc.line_of_business_category = (CASE WHEN @threshold='N' THEN 'AAA' ELSE 'BBB' END)
WHERE
gii.inventory_item_id = @v_item_id;
Кроме того, он начинает показывать вам, когда у вас могут возникнуть проблемы в отношениях, например, в случае ваших категорий gpc. Я вижу, что таблица не имеет прямого отношения к 1 из других таблиц, а вы выбираете категории, которые затем перекрестно соединяются, что вы хотели?
Конечно, вы можете использовать case
выражение:
select min_price
, s.customization_type
, gii.brand
, gii.item_flag
from item_info gii
, style s
, categories gpc
where isnull(@ordered,getdate()) between gpc.start_date and isnull(gpc.end_date, dateadd(day, 1, getdate()))
and gii.segment1 = s.style_number
and gpc.line_of_business_category = case when @threshold='N' then 'AAA' else 'BBB' end
and gii.inventory_item_id = @v_item_id;
Вы действительно можете использовать оператор CASE в своем запросе, как показано ниже, с минимальным изменением запроса:
select min_price
, s.customization_type
, gii.brand
, gii.item_flag
from item_info gii
, style s
, categories gpc
where isnull(@ordered,getdate())
between gpc.start_date and isnull(gpc.end_date, dateadd(day, 1, getdate()))
and gii.segment1 = s.style_number
and 1 = CASE
WHEN @threshold='N' AND gpc.line_of_business_category = 'AAA'
THEN 1
WHEN @threshold <> 'N' AND gpc.line_of_business_category = 'BBB'
THEN 1
ELSE 0
END
and gii.inventory_item_id = @v_item_id;
Просто используйте
and ( (@threshold ='N' AND gpc.line_of_business_category = 'AAA')
or (@threshold<>'N' AND gpc.line_of_business_category = 'BBB') )
Полный запрос будет
select min_price
, s.customization_type
, gii.brand
, gii.item_flag
from item_info gii
, style s
, categories gpc
where isnull(@ordered,getdate()) between gpc.start_date and isnull(gpc.end_date, dateadd(day, 1, getdate()))
and gii.segment1 = s.style_number
and ( (@threshold ='N' AND gpc.line_of_business_category = 'AAA')
or (@threshold<>'N' AND gpc.line_of_business_category = 'BBB') )
and gii.inventory_item_id = @v_item_id;