#sql-server
#sql-сервер
Вопрос:
Ниже приведен мой SP:
Alter PROCEDURE GetList
(
@FromDate date = null,
@ToDate date = null
)
AS
Select * FROM CallList c
Where c.CallDate > @FromDate and c.CallDate < @ToDate
Если не было передано фильтра по дате, я хочу получить все записи.
Как бы я это сделал?
Ответ №1:
Вы можете сделать это:
SELECT * FROM CallList c
WHERE (c.CallDate > @FromDate OR @FromDate IS NULL) AND
(c.CallDate < @ToDate OR @ToDate IS NULL)
Это также оставляет вас открытым для возможности оставить одну из дат нулевой, а другую — нет.
Комментарии:
1. Остерегайтесь запросов с перегрузкой ИЛИ — они имеют тенденцию кусаться.
Ответ №2:
вы бы сделали следующее
SELECT *
FROM CallList AS C
WHERE (@FromDate IS NULL OR c.CallDate > @FromDate)
AND (@ToDate IS NULL OR c.CallDate < @ToDate)
Комментарии:
1. по сути, мы говорим, что если параметр равен null, игнорируйте его. В противном случае он должен соответствовать критериям, следующим за ИЛИ
Ответ №3:
Пара жизнеспособных вариантов:
Вы могли бы установить, что @FromDate
и @ToDate
равны очень ранней или очень поздней дате, соответственно, они равны NULL.
Вы могли бы использовать sp_executesql и создать динамическую строку запроса с параметрами по мере необходимости, например
DECLARE @Sql NVARCHAR(MAX) = 'SELECT * FROM CallList C WHERE 1 = 1 '
IF @FromDate IS NOT NULL
BEGIN
SET @Sql = ' AND C.CallDate > @xFromDate'
END
IF @ToDate IS NOT NULL
BEGIN
SET @Sql = ' AND C.CallDate < @xToDate'
END
EXEC sp_executesql @Sql, N'@xFromDate DATETIME, @xToDate DATETIME', @xFromDate = @FromDate, @xToDate = @ToDate
Этот последний подход работает лучше, чем повсеместное использование ORS, поскольку запросы, включающие ORS, неизменно в конечном итоге очень плохо оптимизируются — они могут хорошо работать для определенного набора параметров, но, как правило, не являются универсальными.
Комментарии:
1. 1 за правильное построение строки SQL с параметрами в ней, а затем с использованием sp_executesql — Так много людей просто вводят значения и игнорируют последствия этого.
2. Голосую за то, чтобы подчеркнуть важность отказа от введения значений. 🙂
3. Хотя я думаю, что у вас есть правильная методология с динамическим SQL, это подход с использованием кувалды, когда все, что вам нужно, это молоток. Динамического SQL следует избегать, насколько это возможно.
4. @N8 — True — это приводит к сложности в обслуживании кода, для этого простого запроса, возможно, это излишне. Если CallList содержит миллионы строк, это может стоить того — несколько тысяч, тогда, вероятно, нет. Для хранимых процедур (обычно поисковых запросов), которые принимают множество параметров, которые могут иметь значение NULL, а могут и не иметь, динамический SQL часто спасает жизнь.
5. хех, о, я тоже НЕНАВИЖУ подобные процедуры! Я согласен с вами, хотя с 10-м параметром управлять этим становится просто кошмаром. самое сложное, с чем можно справиться, — это чертово перехват параметров!
Ответ №4:
Попробуйте следующее:
SELECT
*
FROM
CallList c
WHERE
( @FromDate is null AND @ToDate is null ) OR
( @FromDate is null AND c.CallDate < @ToDate ) OR
( @ToDate is null AND c.CallDate > @FromDate) OR
( c.CallDate > @FromDate AND c.CallDate < @ToDate )
Кроме того, если вы искали пересечение между двумя периодами, не забудьте выбрать более поздний FromDate и более ранний ToDate.
Ответ №5:
Динамический sql дополняется каждый раз, поэтому не используйте динамический sql
select * from calllist As c
where (c.CallDate < @ToDate or @ToDate is null)
and (c.CallDate > @FromDate or @FromDate is null)
Ответ №6:
DECLARE @BgnDate date,
@EndDate date
SELECT @BgnDate = MIN(c.CallDate), @EndDate = MIN(c.CallDate) FROM CallList
Select * FROM CallList c
Where c.CallDate > ISNULL(@FromDate,@BgnDate)
and c.CallDate < ISNULL(@ToDate,@EndDate)
Ответ №7:
Вы также могли бы использовать BETWEEN
(сокращенное обозначение меньше или равно и больше или равно):
declare @ToDate varchar(12)=null,
@FromDate varchar(12)=null
select * from calllist As c where c.CallDate between
CONVERT(datetime, isnull(@ToDate,c.CallDate))
and CONVERT(datetime,isnull(@FromDate,c.CallDate))
Комментарии:
1. Если возможно, предоставьте некоторую дополнительную информацию (кроме просто SQL), чтобы объяснить, почему это лучше / отличается от других ответов, спасибо.
2. Между сокращениями LTE и GTE, между переводом в GTE и LTE во время компиляции запроса, поэтому я думаю, что время выполнения должно быть одинаковым, я просто даю краткий ответ на это