2009-10-05 12 views
6

przy użyciu programu SQL Server 2008. Mam przechowywany proces, który ma datę początkową i końcową jako parametry wejściowe dla zakresu dat.Pojedyncze zapytanie sql, które może obsłużyć zarówno pusty, jak i wartościowy zakres dat w serwerze sql

Poszukuje się pojedynczego zapytania , które zawiera datę rozpoczęcia i zakończenia w klauzuli where, która może obsłużyć oba przypadki, w których daty są albo zerowe, albo obie mają wartości.

Nie chcę używać instrukcji JEŻELI.

+0

mógłbyś pisać co byłoby zapytanie wyglądać być oba parametry zdefiniowane? – Quassnoi

Odpowiedz

12
WITH limits AS 
     (
     SELECT COALESCE(@startDate, MIN(mydate)) AS startDate, COALESCE(@endDate, MAX(mydate)) AS endDate 
     FROM mytable 
     ) 
SELECT m.* 
FROM limits 
JOIN mytable m 
ON  mydate BETWEEN startDate AND endDate 

To będzie najbardziej skuteczny, jeśli istnieje indeks na mydate, ponieważ warunek ten jest sargable i użyje Index Seek.

Jeśli nie ma indeksu, należy użyć konstrukcji zaproponowanych przez innych.

+1

Nice. Podoba mi się ograniczenie zakresu dat do tego, co już jest w tabeli. – dnagirl

+0

Uważaj: połączenia min/max() są drogie w przypadku braku dobrego indeksu daty (który użytkownik nie określił wprost). – DVK

+0

Takich, jak ja nienawidzę głosować przeciwko sobie, to wydaje się być najlepsze, zakładając, że istnieje indeks . +1 – wcm

9

Można to zrobić:

SELECT blah 
FROM MyTable 
WHERE 
    (@startDate IS NULL OR MyTable.StartDate >= @startDate) 
    AND (@endDate IS NULL OR MyTable.EndDate <= @endDate) 

Ale należy pamiętać, że duża liczba parametrów i klauzule, jak może to prowadzić do nieprawidłowego pamięci podręcznej planów kwerend. Na SO jest wiele pytań dotyczących niepoprawnych planów zapytań i parametru "podsłuchiwanie".

4

odpowiedź Quassnoi jest prawdopodobnie najlepsza, ale oto kolejny odbioru:

SELECT * 
FROM MyTable 
WHERE 
    MyTable.StartDate >= ISNULL(@startDate, MyTable.StartDate) 
    AND MyTable.EndDate <= ISNULL(@startDate, MyTable.EndDate) 
+1

Pamiętaj, że to zapobiega używaniu indeksu. – recursive

+0

Myślę, że jest to nieco łatwiejsze do odczytania, ale myślę, że rekursywne jest poprawne. – wcm

+0

+1 - pomocny, ale rekursywny stanowi dobry punkt w odniesieniu do indeksu. –

2
SELECT * 
FROM MyTable 
WHERE 
    MyTable.StartDate >= COALESCE(MyTable.StartDate, "1/1/1900") 
    /* Date selected as earliest plausible constant to avoid min() lookup */ 

AND MyTable.EndDate <= COALESCE(MyTable.EndDate, "1/1/3001") 
    /* Date selected as latest plausible constant to avoid max() lookup */ 

Musisz wybrać odpowiednie stałe dla app/domeny, oczywiście. To trochę ryzykowne, jeśli nie masz stałych wystarczająco szerokich, ale o wiele szybszych niż wyraźnie wyglądających min/maks ze stołu, a większość aplikacji/domen ma całkiem dobrze zdefiniowane ramki.

1
SELECT 
    Column1,.... 
    FROM MyTable 
    WHERE MyTable.StartDate>=COALESCE(@startDate,CONVERT(datetime,'01/01/1753')) 
     AND MyTable.EndDate<=COALESCE(@endDate,CONVERT(datetime,'12/31/9999')) 

również tutaj jest bardzo obszerny artykuł na ten temat:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

obejmuje wszystkie problemy i sposoby próbuje pisać zapytania z wielu opcjonalnych warunków wyszukiwania

tutaj jest spis treści:

Introduction 
     The Case Study: Searching Orders 
     The Northgale Database 
    Dynamic SQL 
     Introduction 
     Using sp_executesql 
     Using the CLR 
     Using EXEC() 
     When Caching Is Not Really What You Want 
    Static SQL 
     Introduction 
     x = @x OR @x IS NULL 
     Using IF statements 
     Umachandar's Bag of Tricks 
     Using Temp Tables 
     x = @x AND @x IS NOT NULL 
     Handling Complex Conditions 
    Hybrid Solutions – Using both Static and Dynamic SQL 
     Using Views 
     Using Inline Table Functions 
    Conclusion 
    Feedback and Acknowledgements 
    Revision History 
0

Dla wartości maksymalnej:

Case when @a > @b or @b is null then @a else @b end. 

Obsługuje także wartości null.

Proste.

1

Można to zrobić

SELECT blah 
FROM MyTable 
WHERE 
1 = case 
     when @startDate IS NOT NULL then MyTable.Date >= @startDate 
    else 1 end 
AND 
1 = case 
     when @endDate IS NOT NULL then MyTable.Date <= @endDate 
    else 1 end 

lub

SELECT blah 
FROM MyTable 
WHERE 
(
    (@startDate is not null and @endDate is not null and MyTable.Date between @startDate and @endDate) 
    or 
    (@startDate is null and @endDate is null) 
) 
Powiązane problemy