WHERE Klauzula, aby znaleźć wszystkie rekordy w określonym miesiącu

87

Chcę mieć możliwość nadania procedurze składowanej miesiąca i roku i zwrócenia wszystkiego, co dzieje się w tym miesiącu. Jak to zrobić, ponieważ nie mogę porównywać, ponieważ niektóre miesiące mają różną liczbę dni itp.?

Jak najlepiej to zrobić? Czy mogę po prostu poprosić o porównanie na podstawie roku i miesiąca?

Dzięki.

Tarks
źródło

Odpowiedzi:

186

Myślę, że funkcja, której szukasz, to MONTH(date). Prawdopodobnie będziesz też chciał użyć „YEAR” .

Załóżmy, że masz tabelę o nazwie, thingsktóra wygląda mniej więcej tak:

id happend_at
-- ----------------
1  2009-01-01 12:08
2  2009-02-01 12:00
3  2009-01-12 09:40
4  2009-01-29 17:55

Powiedzmy, że chcesz wykonać polecenie, aby znaleźć wszystkie rekordy, które mają w happened_atciągu miesiąca 2009/01 (styczeń 2009). Zapytanie SQL wyglądałoby tak:

SELECT id FROM things 
   WHERE MONTH(happened_at) = 1 AND YEAR(happened_at) = 2009

Który zwróciłby:

id
---
1
3
4
Shalom Craimer
źródło
14
W rzeczy samej ! Dla wszystkich zainteresowanych „Funkcje DZIEŃ, MIESIĄC i ROK są synonimami odpowiednio CZĘŚCI DANYCH (dd, data), CZĘŚCI DANYCH (mm, data) i CZĘŚCI DANYCH (rr, data)”.
Tarks
17

Korzystanie z funkcji MIESIĄC i ROK, jak sugerowano w większości odpowiedzi, ma tę wadę, że SQL Server nie będzie w stanie użyć żadnego indeksu, który może znajdować się w kolumnie daty. Może to spowodować utratę wydajności przy dużym stole.

Byłbym skłonny przekazać wartość DATETIME (np. @StartDate) do procedury składowanej, która reprezentuje pierwszy dzień miesiąca, który Cię interesuje.

Następnie możesz użyć

SELECT ... FROM ...
WHERE DateColumn >= @StartDate 
AND DateColumn < DATEADD(month, 1, @StartDate)

Jeśli musisz przekazać miesiąc i rok jako oddzielne parametry do procedury składowanej, możesz wygenerować DATETIME reprezentujący pierwszy dzień miesiąca za pomocą funkcji RZUTUJ i KONWERTUJ, a następnie postępuj jak powyżej. Jeśli to zrobisz, poleciłbym napisanie funkcji, która generuje DATETIME z liczb całkowitych rok, miesiąc, dzień, np. Następujące z bloga SQL Server .

create function Date(@Year int, @Month int, @Day int)
returns datetime
as
    begin
    return dateadd(month,((@Year-1900)*12)+@Month-1,@Day-1)
    end
go

Zapytanie staje się wtedy:

SELECT ... FROM ...
WHERE DateColumn >= Date(@Year,@Month,1)
AND DateColumn < DATEADD(month, 1, Date(@Year,@Month,1))
Joe
źródło
1
Tak, zgadzam się z @joe "Używanie funkcji MIESIĄC i ROK, jak sugerowano w większości odpowiedzi, ma tę wadę, że SQL Server nie będzie w stanie użyć żadnego indeksu, który może znajdować się w kolumnie z datami. Może to obniżyć wydajność dużej tabeli . ”
Raghav
Czy mógłbym coś dodać? Jeśli deklarujesz „@StartDate w parametrze, to ja również zadeklarowałbym„ @EndDate ”i umieściłbym tam DATEADD, zamiast wykonywać obliczenia matematyczne w każdym wierszu przez SQL.
DataGirl
@DataGirl - ciekawy punkt. Założyłem, że funkcja DATEADD będzie traktowana jako stała czasu wykonywania i oceniana tylko raz. Jeśli są co do tego wątpliwości, zadeklarowanie @EndDatesprawi , że będzie to wyraźne.
Joe
4

Jeszcze jedna wskazówka bardzo prosta. Możesz także użyć funkcji to_char , spójrz:

Na miesiąc:

to_char (zdarzało się_at , 'MM') = 01

Na rok:
to_char ( happ_at , „RRRR”) = 2009

Na dzień:

to_char ( happ_at , 'DD') = 01

Funkcja to_char jest obsługiwana przez język sql, a nie przez jedną konkretną bazę danych.

Mam nadzieję, że komuś bardziej pomogę ...

Abs!

Marcelo Rebouças
źródło
1
Mam wrażenie, że działa to tylko na Oracle, jest naprawdę specyficzne. SQL Server zdecydowanie tego nie obsługuje.
Carol,
3

Jako alternatywa dla funkcji MIESIĄC i ROK, będzie też działać zwykła klauzula WHERE:

select *
from yourtable
where '2009-01-01' <= datecolumn and datecolumn < '2009-02-01'
Andomar
źródło
1

Czy mogę po prostu poprosić o porównanie na podstawie roku i miesiąca?

Możesz. Oto prosty przykład użycia przykładowej bazy danych AdventureWorks ...

DECLARE @Year       INT
DECLARE @Month      INT

SET @Year = 2002
SET @Month = 6

SELECT 
    [pch].* 
FROM 
    [Production].[ProductCostHistory]   pch
WHERE
    YEAR([pch].[ModifiedDate]) = @Year
AND MONTH([pch].[ModifiedDate]) = @Month
Leniwy DBA
źródło
1

Łatwiej mi jest przekazać wartość jako tymczasowy typ danych (np. DATETIME), A następnie użyć funkcji czasowej, w szczególności DATEADDi DATEPART, aby znaleźć datę początkową i końcową dla okresu, w tym przypadku miesiąc, np. Znajduje to datę początkową i datę końcową dla bieżącego miesiąca wystarczy podstawić CURRENT_TIMESTAMPza siebie parametr typu DATETIME(zwróć uwagę, że wartość 1990-01-01 jest całkowicie dowolna):

SELECT DATEADD(M, 
          DATEDIFF(M, '1990-01-01T00:00:00.000', CURRENT_TIMESTAMP), 
          '1990-01-01T00:00:00.000'), 
       DATEADD(M, 
          DATEDIFF(M, '1990-01-01T00:00:00.000', CURRENT_TIMESTAMP), 
          '1990-01-31T23:59:59.997')
onedaywhen
źródło
0

Coś takiego powinno to zrobić:

select * from yourtable where datepart(month,field) = @month and datepart(year,field) = @year

Alternatywnie możesz podzielić miesiąc i rok na osobne kolumny podczas tworzenia rekordu, a następnie dokonać wyboru.

Iain

Świątynia
źródło
0

Jednym ze sposobów byłoby utworzenie zmiennej, która reprezentuje pierwszy dzień miesiąca (np. 5/1/2009), albo przekazanie jej do procesu, albo zbudowanie (konkatenacja miesiąca / 1 / rok). Następnie użyj funkcji DateDiff.

WHERE DateDiff(m,@Date,DateField) = 0

Zwróci wszystko, co ma pasujący miesiąc i rok.

Mike Bennett
źródło
-4
SELECT * FROM yourtable WHERE yourtimestampfield LIKE 'AAAA-MM%';

Gdzie AAAAjest rok, który chcesz i MMmiesiąc, który chcesz

user2022742
źródło