2014-10-07 6 views
15

Mam problem z określeniem najlepszego sposobu porównywania dat w SQL na podstawie tylko miesiąca i roku.Porównanie danych SQL Server na podstawie tylko miesiąca i roku.

Wykonujemy obliczenia na podstawie dat, a ponieważ fakturowanie odbywa się co miesiąc, data miesiąca spowodowała większe utrudnienia.

Przykładowo

DECLARE @date1 DATETIME = CAST('6/15/2014' AS DATETIME), 
     @date2 DATETIME = CAST('6/14/2014' AS DATETIME) 

SELECT * FROM tableName WHERE @date1 <= @date2 

Powyższy przykład nie zwróciło żadnych wiersze od @ date1 jest większa niż @ data2. Więc chciałbym znaleźć sposób na wyjście z równania.

Podobnie, poniższa sytuacja sprawia mi żal z tego samego powodu.

DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME), 
     @date2 DATETIME = CAST('6/15/2014' AS DATETIME), 
     @date3 DATETIME = CAST('7/1/2014' AS DATETIME) 

SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3 

Przeprowadziłem inline konwersje dat, aby uzyskać pierwszy dzień i ostatni dzień miesiąca dla określonej daty.

SELECT * 
FROM tableName 
WHERE date2 BETWEEN 
    DATEADD(month, DATEDIFF(month, 0, date1), 0) -- The first day of the month for date1 
    AND 
    DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, date2) + 1, 0)) -- The lastday of the month for date3 

Musi być łatwiejszy sposób na zrobienie tego. Jakieś sugestie?

+1

Której wersji SQL Server? – christiandev

+0

@christiandev Używamy SQL 2008. –

+1

Na marginesie, jeśli nie korzystasz z części czasu, możesz użyć typu danych "DATA". – christiandev

Odpowiedz

15

Aby obsłużyć nierówności, takie jak między, lubię konwertować datę/czas na reprezentację RRRRMM, jako ciąg lub liczbę całkowitą. Na tym przykładzie:

DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME), 
     @date2 DATETIME = CAST('6/15/2014' AS DATETIME), 
     @date3 DATETIME = CAST('7/1/2014' AS DATETIME); 

SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3; 

chciałbym napisać kwerendę jako:

SELECT * 
FROM tableName 
WHERE year(@date2) * 100 + month(@date2) BETWEEN year(@date1) * 100 + month(@date1) AND 
               year(@date3) * 100 + month(@date1); 
6

Możesz dołączyć na MONTH i YEAR wartości tych terminach:

SELECT * 
FROM tableName 
WHERE YEAR(@date1) = YEAR(@date2) AND MONTH(@date1) = MONTH(@date2) 
+2

+1 pokonałeś mnie o kilka sekund :-) – Tanner

+0

Dziękuję za odpowiedź, ale to nie dotyczy zakresów dat. Na przykład "WHERE date1 BETWEEN date2 AND date3" –

+1

@AndyEvans Odsunął moją edycję, na drugi myśli o zakresach lepiej użyć odpowiedzi z GordonLinoff. – DavidG

13

można filtrować miesiąc i rok danego dnia do bieżącej daty tak:

SELECT * 
FROM tableName 
WHERE month(date2) = month(getdate()) and year(date2) = year(getdate()) 

Wystarczy zastąpić metoda GETDATE() z żądaną datą.

+1

Ciągle zasługujesz na +1 chociaż :) – DavidG

+0

Dziękuję za odpowiedź, ale to nie dotyczy zakresów dat. Na przykład "WHERE date1 BETWEEN date2 AND date3" –

+1

@AndyEvans, więc chcesz wszystkie rekordy, w których data przypada w ciągu jednego miesiąca w roku? – Tanner

8

Po pierwsze, chciałbym użyć formatu dla dat, które jest jednoznaczne, jak standardowy 'YYYYMMDD' a nie masz '6/15/2014' używam. blog Aaron Bertranda wyjaśnia znacznie lepiej niż ja, różne sposoby, to może się nie udać:
Bad habits to kick : mis-handling date/range queries

Dla konkretnego problemu, Twoja ostatnia kwerenda, która stwierdzi, pierwsze i ostatnie dni miesięcy (dla DATE1 i date3), jest moim zdaniem na dobrej drodze. Wystarczy chociaż pierwszych dniach miesięcy (pierwszy dzień DATE1 i pierwszego dnia następnego miesiąca za date3), jeśli uniknąć zło BETWEEN: What do BETWEEN and the devil have in common?

SELECT * 
FROM tableName 
WHERE date2 >= DATEADD(month, DATEDIFF(month, '19000101', @date1), '19000101') 
    AND date2 < DATEADD(month, 1+DATEDIFF(month, '19000101', @date3), '19000101') ; 

Kwerenda działa jak to jest, bez względu na typ danych od date2 (DATE, DATETIME,).

Punkt bonusowy, indeksy na date2 zostaną uznane przez optymalizatora w ten sposób.


Poprawa, zgodnie z (jeszcze innej) Aarona blogu, aby uniknąć problemu z oszacowania liczności podczas oceniania wyrażeń z DATEDIFF():
Performance Surprises and Assumptions : DATEDIFF

SELECT * 
FROM tableName 
WHERE date2 >= CONVERT(DATE, DATEADD(day, 1 - DAY(@date1), @date1)) 
    AND date2 < DATEADD(month, 1, 
         CONVERT(DATE, DATEADD(day, 1 - DAY(@date3), @date3))) ;