Truy vấn postgresql giữa các phạm vi ngày


126

Tôi đang cố gắng truy vấn db postgresql của mình để trả về kết quả có ngày tháng và năm nhất định. Nói cách khác, tôi muốn tất cả các giá trị cho một tháng-năm.

Cách duy nhất tôi có thể làm cho đến nay là như sau:

SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN '2014-02-01' AND '2014-02-28'

Vấn đề với điều này là tôi phải tính toán ngày đầu tiên và ngày cuối cùng trước khi truy vấn bảng. Có cách nào đơn giản hơn để làm điều này không?

Cảm ơn


Khoảng thời gian đó luôn là một tháng hay có thể là, bạn có thể bắt đầu từ ngày 15 và kết thúc vào ngày 7 của tháng tiếp theo?
frlan

Câu trả lời:


202

Với ngày (và giờ) nhiều thứ trở nên đơn giản hơn nếu bạn sử dụng >= start AND < end.

Ví dụ:

SELECT
  user_id
FROM
  user_logs
WHERE
      login_date >= '2014-02-01'
  AND login_date <  '2014-03-01'

Trong trường hợp này, bạn vẫn cần phải tính toán ngày bắt đầu của tháng bạn cần, nhưng điều đó nên được chuyển thẳng theo bất kỳ cách nào.

Ngày kết thúc cũng được đơn giản hóa; chỉ cần thêm đúng một tháng. Không lộn xộn với 28, 30, 31, v.v.


Cấu trúc này cũng có ưu điểm là có thể duy trì việc sử dụng các chỉ mục.


Nhiều người có thể đề xuất một biểu mẫu như sau, nhưng họ không sử dụng chỉ mục:

WHERE
      DATEPART('year',  login_date) = 2014
  AND DATEPART('month', login_date) = 2

Điều này liên quan đến việc tính toán các điều kiện cho mọi hàng đơn lẻ trong bảng (quét) và không sử dụng chỉ mục để tìm phạm vi các hàng sẽ khớp (tìm kiếm phạm vi).


1
Cách tiếp cận đầu tiên cần xoay quanh số tháng (thay vì ngày) f.ex. 2014-12-01& 2015-01-01. Cái thứ hai cũng có thể được lập chỉ mục, nhưng điều đó không tầm thường, tôi thừa nhận - EXTRACT()có vẻ tương thích hơn.
pozs

1
Bạn có thể tránh tính toán ngày tháng trong ứng dụng của mình bằng cách sử dụng khoảng thời gian. ví dụ: WHERE login_date> = '2014-02-01' AND login_date <'2014-02-01' :: date + INTERVAL '1 tháng' Điều này vẫn sử dụng các chỉ mục trong khi đơn giản hóa mã của bạn.
baswell,

53

Từ PostreSQL 9.2 Các loại phạm vi được hỗ trợ. Vì vậy, bạn có thể viết như sau:

SELECT user_id
FROM user_logs
WHERE '[2014-02-01, 2014-03-01]'::daterange @> login_date

điều này sẽ hiệu quả hơn so với so sánh chuỗi


23

Chỉ trong trường hợp ai đó hạ cánh ở đây ... kể từ 8.1, bạn chỉ cần sử dụng:

SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN SYMMETRIC '2014-02-01' AND '2014-02-28'

Từ các tài liệu:

BETWEEN SYMMETRIC giống như BETWEEN ngoại trừ không có yêu cầu rằng đối số ở bên trái của AND phải nhỏ hơn hoặc bằng đối số ở bên phải. Nếu không, hai đối số đó sẽ tự động được hoán đổi vị trí, do đó, một dải ô trống luôn được ngụ ý.


-1
SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN '2014-02-01' AND '2014-03-01'

Giữa các từ khóa hoạt động đặc biệt cho một ngày. nó giả định thời gian là lúc 00:00:00 (tức là nửa đêm) cho các ngày.


-14

Đọc tài liệu.

http://www.postgresql.org/docs/9.1/static/functions-datetime.html

Tôi đã sử dụng một truy vấn như vậy:

WHERE
(
    date_trunc('day',table1.date_eval) = '2015-02-09'
)

hoặc là

WHERE(date_trunc('day',table1.date_eval) >='2015-02-09'AND date_trunc('day',table1.date_eval) <'2015-02-09')    

Juanitos Ingenier.


2
Điều này không trả lời chính xác câu hỏi. Câu hỏi yêu cầu ngày dựa trên tháng và năm.
Ram
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.