NHÓM truy vấn MySQL theo ngày / tháng / năm


649

Có thể thực hiện một truy vấn đơn giản để đếm số lượng bản ghi tôi có trong một khoảng thời gian xác định như một năm, tháng hoặc ngày, có một TIMESTAMPtrường, như:

SELECT COUNT(id)
FROM stats
WHERE record_date.YEAR = 2009
GROUP BY record_date.YEAR

Hoặc thậm chí:

SELECT COUNT(id)
FROM stats
GROUP BY record_date.YEAR, record_date.MONTH

Để có một thống kê hàng tháng.

Cảm ơn!


1
Tôi đoán nó được cho là GROUP BY record_date.MONTHtrong đoạn mã đầu tiên của bạn?
chiccodoro

Câu trả lời:


1012
GROUP BY YEAR(record_date), MONTH(record_date)

Kiểm tra các chức năng ngày và thời gian trong MySQL.


27
Bạn có thể muốn thêm một cột bổ sung để thêm rõ ràng trong một số trường hợp, chẳng hạn như hồ sơ kéo dài vài năm. CHỌN COUNT (event_id), DATE_FORMAT (event_start, '% Y /% m')
Ric

Ví dụ hoàn chỉnh đơn giản: SELECT count(*), record_date FROM anytable WHERE anytable.anycolumn = 'anycondition' GROUP BY YEAR(record_date), month(record_date);lưu ý: record_date là loại ngày TIMESTAMP
đổi tên vào

Có lẽ đáng để đề cập đến điều này đã không chạy trên MySQL 5.7 của tôi với một cột bí danh COUNT (không có lỗi, tôi không có kết quả nào). Khi tôi thay đổi để chọn các trường có bí danh, sau đó tôi có thể nhóm theo bí danh. Đây là hình ảnh docker MySQL 5.7 tiêu chuẩn đang chạy trong môi trường cục bộ vì vậy tôi không biết tại sao nó không bị lỗi hoặc trả về kết quả.
MrMesees

3
Trời ơi, nếu tôi biết điều này sớm hơn ... rất nhiều dòng PHP để làm một cái gì đó mysql có thể làm trong một dòng.
đêm

230
GROUP BY DATE_FORMAT(record_date, '%Y%m')

Lưu ý (chủ yếu, để downvoters tiềm năng). Hiện tại, điều này có thể không hiệu quả như các đề xuất khác. Tuy nhiên, tôi để nó như một giải pháp thay thế, và cũng vậy, nó có thể phục vụ trong việc xem các giải pháp khác nhanh hơn như thế nào. (Đối với bạn không thể thực sự nói nhanh từ chậm cho đến khi bạn thấy sự khác biệt.) Ngoài ra, khi thời gian trôi qua, những thay đổi có thể được thực hiện đối với công cụ của MySQL liên quan đến tối ưu hóa để tạo ra giải pháp này, ở một số (có lẽ, không phải vậy xa) điểm trong tương lai, để trở nên khá tương đương về hiệu quả với hầu hết những người khác.


3
Tôi có cảm giác rằng điều này sẽ không hoạt động tốt vì một chức năng định dạng sẽ không thể sử dụng một chỉ mục trên cột ngày.
Sonny

@Stv: Bạn có thể muốn xem xét câu trả lời của @ fu-chi . Theo như tôi có thể nói, các biểu thức nhóm trong cả câu trả lời và câu trả lời của tôi đánh giá cùng một điều nhưng EXTRACT()có thể hiệu quả hơn DATE_FORMAT(). (Tuy nhiên, tôi không có MySQL để kiểm tra thích hợp.)
Andriy M

45

thử cái này

SELECT COUNT(id)
FROM stats
GROUP BY EXTRACT(YEAR_MONTH FROM record_date)

Hàm EXTRACT (đơn vị TỪ ngày) sẽ tốt hơn khi sử dụng ít nhóm hơn và hàm trả về một giá trị số.

Điều kiện so sánh khi nhóm sẽ nhanh hơn hàm DATE_FORMAT (trả về giá trị chuỗi). Hãy thử sử dụng hàm | trường trả về giá trị không phải chuỗi cho điều kiện so sánh SQL (WHERE, HAVING, ORDER BY, GROUP BY).


43

Tôi đã thử sử dụng câu lệnh 'WHERE' ở trên, tôi nghĩ rằng nó đúng vì không ai sửa nó nhưng tôi đã sai; sau một số tìm kiếm tôi phát hiện ra rằng đây là công thức phù hợp cho câu lệnh WHERE để mã trở nên như sau:

SELECT COUNT(id)  
FROM stats  
WHERE YEAR(record_date) = 2009  
GROUP BY MONTH(record_date)

30

Nếu tìm kiếm của bạn đã qua vài năm và bạn vẫn muốn nhóm hàng tháng, tôi đề nghị:

phiên bản 1:

SELECT SQL_NO_CACHE YEAR(record_date), MONTH(record_date), COUNT(*)
FROM stats
GROUP BY DATE_FORMAT(record_date, '%Y%m')

phiên bản # 2 (hiệu quả hơn) :

SELECT SQL_NO_CACHE YEAR(record_date), MONTH(record_date), COUNT(*)
FROM stats
GROUP BY YEAR(record_date)*100 + MONTH(record_date)

Tôi đã so sánh các phiên bản này trên một bảng lớn với 1.357.918 hàng () và phiên bản thứ 2 dường như có kết quả tốt hơn.

version1 (trung bình 10 thực thi) : 1,404 giây
version2 (trung bình 10 thực thi) : 0,780 giây

( SQL_NO_CACHEkhóa được thêm vào để ngăn MySQL khỏi việc GỬI các truy vấn.)


1
Xem xét đưa đề xuất của @ fu-chi vào các thử nghiệm của bạn, nó có thể chứng minh hiệu quả hơn nữa. Ngoài ra, bạn đã thử nghiệm GROUP BY YEAR(record_date)*100 + MONTH(record_date), nhưng tại sao không thử nghiệm GROUP BY YEAR(record_date), MONTH(record_date)là tốt?
Andriy M

2
Nếu bạn sử dụng COUNT (1) insteed COUNT (*), nó sẽ còn nhanh hơn nữa và dữ liệu kết quả là như nhau.
Pa0l0

2
Đó là gì *100trên Versión # 2? Cảm ơn trước.
Avión

1
*100đếnYEAR(record_date)*100 + MONTH(record_date) == DATE_FORMAT(record_date, '%Y%m')
Phú Duy

17

Nếu bạn muốn nhóm theo ngày trong MySQL thì hãy sử dụng mã dưới đây:

 SELECT COUNT(id)
 FROM stats
 GROUP BY DAYOFMONTH(record_date)

Hy vọng điều này sẽ tiết kiệm thời gian cho những người sẽ tìm thấy chủ đề này.


6
Điều quan trọng cần lưu ý là bạn cũng cần phải nhóm theo MONTH(record_date)tài khoản trong nhiều tháng.
Webnet

14

Nếu bạn muốn lọc các bản ghi cho một năm cụ thể (ví dụ 2000) thì hãy tối ưu hóa WHEREmệnh đề như sau:

SELECT MONTH(date_column), COUNT(*)
FROM date_table
WHERE date_column >= '2000-01-01' AND date_column < '2001-01-01'
GROUP BY MONTH(date_column)
-- average 0.016 sec.

Thay vì:

WHERE YEAR(date_column) = 2000
-- average 0.132 sec.

Các kết quả được tạo dựa trên bảng chứa 300k hàng và chỉ mục trên cột ngày.

Đối với GROUP BYmệnh đề, tôi đã thử nghiệm ba biến thể so với bảng đã đề cập ở trên; đây là kết quả:

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY YEAR(date_column), MONTH(date_column)
-- codelogic
-- average 0.250 sec.

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY DATE_FORMAT(date_column, '%Y%m')
-- Andriy M
-- average 0.468 sec.

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY EXTRACT(YEAR_MONTH FROM date_column)
-- fu-chi
-- average 0.203 sec.

Người cuối cùng là người chiến thắng.


10

Giải pháp hoàn chỉnh và đơn giản với hiệu suất tương tự nhưng thay thế ngắn hơn và linh hoạt hơn hiện đang hoạt động:

SELECT COUNT(*) FROM stats
-- GROUP BY YEAR(record_date), MONTH(record_date), DAYOFMONTH(record_date)
GROUP BY DATE_FORMAT(record_date, '%Y-%m-%d')

7

Nếu bạn muốn nhận số liệu thống kê hàng tháng với số lượng hàng mỗi tháng của mỗi năm được đặt hàng theo tháng gần nhất, thì hãy thử điều này:

SELECT count(id),
      YEAR(record_date),
      MONTH(record_date) 
FROM `table` 
GROUP BY YEAR(record_date),
        MONTH(record_date) 
ORDER BY YEAR(record_date) DESC,
        MONTH(record_date) DESC

7

Bạn có thể thực hiện điều này một cách đơn giản là hàm Mysql DATE_FORMAT () trong GROUP BY. Bạn có thể muốn thêm một cột bổ sung để thêm rõ ràng trong một số trường hợp, chẳng hạn như hồ sơ kéo dài vài năm sau đó cùng một tháng xảy ra trong các năm khác nhau. Có rất nhiều tùy chọn bạn có thể tùy chỉnh điều này. Xin vui lòng đọc này trước khi bắt đầu. Hy vọng nó sẽ rất hữu ích cho bạn. Đây là truy vấn mẫu cho sự hiểu biết của bạn

SELECT
    COUNT(id),
    DATE_FORMAT(record_date, '%Y-%m-%d') AS DAY,
    DATE_FORMAT(record_date, '%Y-%m') AS MONTH,
    DATE_FORMAT(record_date, '%Y') AS YEAR

FROM
    stats
WHERE
    YEAR = 2009
GROUP BY
    DATE_FORMAT(record_date, '%Y-%m-%d ');

4

Truy vấn sau đây làm việc cho tôi trong Cơ sở dữ liệu Oracle 12c Phiên bản 12.1.0.1.0

SELECT COUNT(*)
FROM stats
GROUP BY 
extract(MONTH FROM TIMESTAMP),
extract(MONTH FROM TIMESTAMP),
extract(YEAR  FROM TIMESTAMP);

2

Tôi thích tối ưu hóa lựa chọn nhóm một năm như vậy:

SELECT COUNT(*)
  FROM stats
 WHERE record_date >= :year 
   AND record_date <  :year + INTERVAL 1 YEAR;

Bằng cách này, bạn chỉ có thể liên kết năm một lần, ví dụ '2009', với một tham số đã đặt tên và không cần phải lo lắng về việc thêm '-01-01'hoặc chuyển '2010'riêng.

Ngoài ra, như có lẽ chúng ta chỉ đếm hàng và idkhông bao giờ NULL, tôi thích COUNT(*)đến COUNT(id).


0

.... group by to_char(date, 'YYYY') -> 1989

.... group by to_char(date,'MM') -> 05

.... group by to_char(date,'DD') ---> 23

.... group by to_char(date,'MON') ---> CÓ THỂ

.... group by to_char(date,'YY') ---> 89


Điều này sẽ rất rất chậm.
Earl3s
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.