Làm thế nào để so sánh ngày trong các trường datetime trong Postgresql?


188

Tôi đã phải đối mặt với một kịch bản kỳ lạ khi so sánh giữa các ngày trong postgresql (phiên bản 9.2.4 trong windows). Tôi có một cột trong bảng của mình nói update_date với loại 'dấu thời gian không có múi giờ'. Khách hàng có thể tìm kiếm trên trường này chỉ với ngày (ví dụ: 2013-05-03) hoặc ngày theo thời gian (ví dụ: 2013-05-03 12:20:00). Cột này có giá trị là dấu thời gian cho tất cả các hàng hiện tại và có cùng một phần ngày (2013-05-03) nhưng khác nhau về phần thời gian.

Khi tôi so sánh qua cột này, tôi nhận được kết quả khác nhau. Giống như sau:

select * from table where update_date >= '2013-05-03' AND update_date <= '2013-05-03' -> No results

select * from table where update_date >= '2013-05-03' AND update_date < '2013-05-03' -> No results

select * from table where update_date >= '2013-05-03' AND update_date <= '2013-05-04' -> results found

select * from table where update_date >= '2013-05-03' -> results found

Câu hỏi của tôi là làm thế nào tôi có thể thực hiện truy vấn đầu tiên để có kết quả, ý tôi là tại sao truy vấn thứ 3 hoạt động mà không phải là truy vấn đầu tiên?

Ai có thể giúp tôi với điều này? Cảm ơn trước.

Câu trả lời:


278

@Nicolai là chính xác về việc truyền và tại sao điều kiện là sai đối với bất kỳ dữ liệu nào. Tôi đoán bạn thích hình thức đầu tiên vì bạn muốn tránh thao tác ngày trên chuỗi đầu vào, đúng không? bạn không cần phải sợ:

SELECT *
FROM table
WHERE update_date >= '2013-05-03'::date
AND update_date < ('2013-05-03'::date + '1 day'::interval);

Cú pháp này ( '2013-05-03'::date'1 day'::interval) PostgreQuery có cụ thể không?
Ngọn lửa băng giá

5
@F FrozenFlame đúng vậy. cú pháp tiêu chuẩn sẽ là CAST('2013-05-03' AS DATE) + CAST('1 day' AS INTERVAL)(IIRC). YMMV về sự tồn tại và hành vi của DATEINTERVAL.
chỉ là ai đó

@F FrozenFlame là chính xác, câu trả lời không hoạt động mà không truyền các chuỗi thành các loại ngày. Một diễn viên vẫn còn mất tích. cần phải được ::DATEthêm vào phần đầu tiên của mệnh đề
where

Sẽ không WHERE update_date::date = '2013-05-03' hoạt động tốt và có thể dễ đọc hơn một chút?
MikeF

@MikeF OP update_dateđã nói vậy timestamp without timezone. tôi giả sử một chỉ số trên cột đó. vị ngữ của bạn sẽ không sử dụng chỉ số đó.
chỉ là ai đó

46

Khi bạn so sánh update_date >= '2013-05-03'các giá trị postgres với cùng loại để so sánh các giá trị. Vì vậy, '2013-05-03' của bạn đã được chuyển thành '2013-05-03 00:00:00'.

Vì vậy, đối với update_date = '2013-05-03 14:45:00' biểu thức của bạn sẽ là:

'2013-05-03 14:45:00' >= '2013-05-03 00:00:00' AND '2013-05-03 14:45:00' <= '2013-05-03 00:00:00'

Cái này luôn false

Để giải quyết vấn đề này, hãy cập nhật update_date tới date:

select * from table where update_date::date >= '2013-05-03' AND update_date::date <= '2013-05-03' -> Will return result

1
truyền mọi update_dategiá trị trong bảng so với truyền giá trị đơn của tham số truy vấn là không hiệu quả khủng khiếp và đảm bảo rằng máy chủ sẽ không thể tận dụng các chỉ mục trên cột đó. Tôi bị cám dỗ đến -1 này.
chỉ là ai đó

3
Có, tôi đồng ý rằng việc truyền từng giá trị là không hiệu quả và bạn có thể cho -1 cho giải pháp này. Nhưng tôi đã mô tả lý do của vấn đề và đã đưa ra ví dụ minh chứng cho vấn đề này. Bây giờ người dùng2866264 biết tại sao truy vấn của anh ta không trả về các hàng dự kiến ​​và sẽ quyết định chính xác giải pháp nào tốt hơn cho trường hợp duy nhất của anh ta.
Nicolai

@Nicolai: Cảm ơn rất nhiều vì câu trả lời của bạn. Nó hoạt động bằng cách làm theo câu trả lời của bạn. Cũng cảm ơn đã giải thích.
dùng2866264

1
@Nicolai - Đưa ra những gì bạn đã nói về Postgres mở rộng ngày theo nghĩa đen đến nửa đêm, nếu mục tiêu là tìm các bản ghi được đánh dấu vào một ngày duy nhất (ngày 3 tháng 5), mã này có chính xác và hiệu quả hơn không: SELECT * FROM my_table WHERE update_date >= '2013-05-03' AND update_date < '2013-05-04'; (Lưu ý việc sử dụng ngày 4 tháng 5 thay vì thứ 3 và với một TÍN HIỆU LỚN thay vì ít hơn hoặc bằng nhau.)
Basil Bourque


2

Sử dụng chuyển đổi ngày để so sánh với ngày: Hãy thử này:

select * from table 
where TO_DATE(to_char(timespanColumn,'YYYY-MM-DD'),'YYYY-MM-DD') = to_timestamp('2018-03-26', 'YYYY-MM-DD')
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.