Published on

January 6, 2017

Использование условных операторов WHERE в SQL Server

Время от времени возникает необходимость использовать условные операторы WHERE в SQL Server. Это означает создание хранимой процедуры, которая фильтрует параметры в зависимости от различных критериев. В прошлом были предприняты попытки использовать операторы IF или динамический T-SQL для достижения этой цели, но эти решения оказались неправильными и не масштабируемыми.

Однако существует решение, которое является саргабельным, что означает, что оно может использовать индексы и работать эффективно. Путем использования оператора “1=@MyCondition” в операторе WHERE, где @MyCondition – это переменная, оптимизатор SQL не распознает его как тавтологию и позволяет использовать различные условия WHERE в зависимости от необходимости.

Давайте рассмотрим пример сценария, чтобы лучше понять эту концепцию. Предположим, нам нужно создать список недель университета по номеру недели и номеру дня недели с использованием общего выражения таблицы (CTE). Проблема заключается в том, чтобы создать этот список с возможностью показывать или скрывать праздники. Вот пример кода CTE:

if @MidDate<@pSchoolEndDate begin
  ;with cte ([Date],Wk,DOW)
  as (
  select @StartDate,@Wk,datepart(dw,@StartDate)
  union all
  select [Date]+1,case when DOW=1 then Wk+1 else Wk end,datepart(dw,[Date]+1)
  from cte
  where [Date]<@MidDate
  )
  insert into @Dates
  select 'W'+cast(Wk as varchar)+'D'+cast(DOW-1 as varchar)
  ,convert(varchar(10),[Date],101)
  ,Wk
  ,DOW
  from cte where 1=1 and datepart(dw,[Date]) not in (1,7) end

В этом примере мы используем CTE для генерации списка недель университета. Переменная @MidDate используется для определения конечной даты недель университета. Переменная @Dates используется для хранения результатов.

Затем нам нужно обработать праздники. Мы можем использовать объединение MERGE JOIN для определения, показывать или скрывать праздники. Вот пример кода MERGE JOIN:

merge @Dates as d
using (select [Date]
        from @Holidays) h on d.[Date]=h.[Date]
when matched and 0=@pShowHolidays then
  delete
when matched and 1=@pShowHolidays then
  update set d.WeekAndDay='Holiday'
when not matched then
  insert([Date])
  values('19000101');

В этом коде мы объединяем таблицу @Dates с таблицей @Holidays на основе даты. Если параметр @pShowHolidays установлен в 0, даты праздников удаляются из таблицы @Dates. Если он установлен в 1, столбец WeekAndDay в таблице @Dates обновляется на ‘Holiday’ для дат праздников. Если дата не найдена ни в одной из таблиц, она вставляется в таблицу @Dates со значением ‘19000101’ по умолчанию.

Теперь давайте сосредоточимся на условном операторе WHERE. В этом примере у нас есть параметр @pUseCondition, который определяет критерии фильтрации. Вот пример условия WHERE:

where (0=@pUseCondition
or (1=@pUseCondition and d1.[WeekDay]='mon')
or (2=@pUseCondition and d1.[WeekDay]='tue')
or (3=@pUseCondition and d1.[WeekDay]='wed')
or (4=@pUseCondition and d1.[WeekDay]='thu')
or (5=@pUseCondition and d1.[WeekDay]='fri')
or (6=@pUseCondition and d1.[WeekDay] in ('mon','wed','fri'))
or (7=@pUseCondition and d1.[WeekDay] in ('tue','thu'))
or (8=@pUseCondition and d.[Date]>=@pEarliestDate)
or (9=@pUseCondition and d1.[WeekDay] in ('mon','fri'))
or (10=@pUseCondition and patindex(@HideDay,d.WeekAndDay)=0)
)

В этом условии у нас есть различные условия в зависимости от значения @pUseCondition. Например, если @pUseCondition установлен в 1, будут возвращены только понедельники. Если он установлен в 6, будут возвращены только понедельники, среды и пятницы. Параметр @pEarliestDate используется для фильтрации дат, которые больше или равны определенной даты. Параметр @HideDay используется для исключения определенных дней недели.

Чтобы использовать этот код, вы можете вызвать хранимую процедуру и передать необходимые параметры. Например:

exec dbo.tp_TestConditional_WHERE_Clause @pSchoolStartDate='20120826'
  ,@pSchoolEndDate='20130531'
  ,@pHolidayList='20121129,20121130,20121225,20130101,20130107'
  ,@pUseCondition=0  -- 0=Нет условий; 1=Пн,2=Вт,3=Ср,4=Чт,5=Пт; 6=Пн,Ср,Пт; 7=Вт,Чт; 8=Наиболее ранняя дата для возврата; 9=Пн,Пт; 10=Исключить @pHideDay
  ,@pShowHolidays=1  -- 0=Скрыть праздники, 1=Показать праздники
  ,@pHideDay=0       -- Использовать номер дня недели (1=Пн,2=Вт,3=Ср,4=Чт,5=Пт) Использовать с @pUseCondition=10
  ,@pEarliestDate='20130228'

Изменяя значение @pUseCondition, вы можете увидеть разные результаты в зависимости от критериев фильтрации.

В заключение, использование условных операторов WHERE в SQL Server может обеспечить гибкость фильтрации данных на основе различных критериев. Путем использования саргабельных условий и динамического SQL можно создать эффективные и масштабируемые решения. Однако перед внедрением этих решений в рабочую среду необходимо тщательно их протестировать и проверить.

Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.