Mệnh đề WHERE để tìm tất cả các bản ghi trong một tháng cụ thể


83

Tôi muốn có thể cung cấp một thủ tục được lưu trữ một Tháng và Năm và nó trả về mọi thứ xảy ra trong tháng đó, làm cách nào để thực hiện việc này vì tôi không thể so sánh giữa một số tháng có số ngày khác nhau, v.v.?

Cách tốt nhất để làm điều này là gì? Cho mình hỏi để so sánh dựa vào năm và tháng được không?

Cảm ơn.

Câu trả lời:


181

Tôi nghĩ rằng chức năng bạn đang tìm kiếm là MONTH(date). Bạn cũng có thể muốn sử dụng "YEAR" .

Giả sử bạn có một bảng có tên thingsgiống như sau:

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

Và giả sử bạn muốn thực thi để tìm tất cả các bản ghi có a happened_attrong tháng 2009/01 (tháng 1 năm 2009). Truy vấn SQL sẽ là:

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

Cái nào sẽ trở lại:

id
---
1
3
4

13
Thật ! Đối với bất kỳ ai quan tâm "Các hàm DAY, MONTH và YEAR lần lượt là từ đồng nghĩa với DATEPART (dd, date), DATEPART (mm, date) và DATEPART (yy, date)."
Tarks

15

Việc sử dụng các hàm MONTH và YEAR như được đề xuất trong hầu hết các câu trả lời có nhược điểm là SQL Server sẽ không thể sử dụng bất kỳ chỉ mục nào có thể có trên cột ngày của bạn. Điều này có thể giết chết hiệu suất trên một bảng lớn.

Tôi có xu hướng chuyển một giá trị DATETIME (ví dụ: @StartDate) cho thủ tục được lưu trữ đại diện cho ngày đầu tiên của tháng mà bạn quan tâm.

Sau đó bạn có thể sử dụng

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

Nếu bạn phải chuyển tháng và năm dưới dạng các tham số riêng biệt cho thủ tục được lưu trữ, bạn có thể tạo DATETIME đại diện cho ngày đầu tiên của tháng bằng cách sử dụng CAST và CONVERT, sau đó tiếp tục như trên. Nếu bạn làm điều này, tôi khuyên bạn nên viết một hàm tạo DATETIME từ các giá trị số nguyên năm, tháng, ngày, ví dụ như sau từ blog 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

Sau đó truy vấn trở thành:

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

1
Ya Tôi đồng ý với @joe "Việc sử dụng các hàm MONTH và YEAR như được đề xuất trong hầu hết các câu trả lời có nhược điểm là SQL Server sẽ không thể sử dụng bất kỳ chỉ mục nào có thể có trên cột ngày của bạn. Điều này có thể giết chết hiệu suất trên một bảng lớn . "
Raghav

Tôi có thể thêm một cái gì đó? Nếu bạn đang khai báo '@StartDate trong một tham số, thì tôi cũng sẽ khai báo' @EndDate và đặt DATEADD ở đó, thay vì để SQL thực hiện phép toán trên mỗi hàng.
DataGirl

@DataGirl - điểm thú vị. Tôi đã giả định rằng hàm DATEADD sẽ được coi là một hằng số thời gian chạy và chỉ được đánh giá một lần. Nếu có nghi ngờ về điều này, việc khai báo @EndDatesẽ làm cho nó rõ ràng.
Joe

3

Để thay thế cho các hàm MONTH và YEAR, mệnh đề WHERE thông thường cũng sẽ hoạt động:

select *
from yourtable
where '2009-01-01' <= datecolumn and datecolumn < '2009-02-01'

3

Thêm một mẹo rất đơn giản. Bạn cũng có thể sử dụng hàm to_char , hãy xem:

Trong tháng:

to_char ( did_at , 'MM') = 01

Trong năm:
to_char ( did_at , 'YYYY') = 2009

Trong ngày:

to_char ( did_at , 'DD') = 01

to_char funcion được cung cấp bởi ngôn ngữ sql chứ không phải bởi một cơ sở dữ liệu cụ thể.

Tôi hy vọng sẽ giúp được mọi người nhiều hơn nữa ...

Áp sát!


1
Tôi có ấn tượng rằng điều này chỉ hoạt động cho Oracle, nó thực sự cụ thể. SQL Server chắc chắn không hỗ trợ nó.
Carol


1

Cho em hỏi để so sánh dựa vào năm và tháng được không ạ?

Bạn có thể. Đây là một ví dụ đơn giản sử dụng cơ sở dữ liệu mẫu 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

1

Tôi thấy việc chuyển một giá trị dưới dạng kiểu dữ liệu tạm thời (ví dụ DATETIME) dễ dàng hơn, sau đó sử dụng chức năng tạm thời, cụ thể là DATEADDDATEPART, để tìm ngày bắt đầu và ngày kết thúc cho khoảng thời gian, trong trường hợp này là tháng, ví dụ: điều này tìm cặp ngày bắt đầu và ngày kết thúc cho tháng hiện tại, chỉ cần thay thế CURRENT_TIMESTAMPcho bạn tham số của loại DATETIME(lưu ý giá trị 1990-01-01 là hoàn toàn tùy ý):

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')

0

Một cái gì đó như thế này nên làm điều đó:

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

Ngoài ra, bạn có thể chia tháng và năm thành các cột của riêng chúng khi tạo bản ghi và sau đó chọn chống lại chúng.

Iain


0

Một cách sẽ là tạo một biến đại diện cho ngày đầu tiên của tháng (tức là ngày 5/1/2009), chuyển nó vào proc hoặc xây dựng nó (nối tháng / 1 / năm). Sau đó sử dụng hàm DateDiff.

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

Điều này sẽ trả về bất kỳ thứ gì có tháng và năm phù hợp.


-4
SELECT * FROM yourtable WHERE yourtimestampfield LIKE 'AAAA-MM%';

Đâu AAAAlà năm bạn muốn và đâu MMlà tháng bạn muốn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.