Để tạo một chuỗi ngày, đây là cách tối ưu :
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
Bổ sung date_trunc()
là không cần thiết. Diễn viên đến date
( day::date
) thực hiện điều đó một cách ngầm định.
Nhưng cũng không có ích lợi gì trong việc truyền các ký tự ngày tháng thành date
tham số đầu vào. Au contraire, timestamp
là sự lựa chọn tốt nhất . Lợi thế về hiệu suất tuy nhỏ, nhưng không có lý do gì để không nắm lấy nó. Và bạn không cần liên quan đến các quy tắc DST (thời gian tiết kiệm ánh sáng ban ngày) cùng với việc chuyển đổi từ date
sang timestamp with time zone
và ngược lại. Xem bên dưới.
Cú pháp ngắn tương đương, ít rõ ràng hơn:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
Hoặc với chức năng set-return trong SELECT
danh sách:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
Các AS
từ khóa được yêu cầu trong các biến thể cuối cùng, Postgres sẽ hiểu sai bí danh cột day
khác. Và tôi sẽ không khuyên biến thể đó trước Postgres 10 - ít nhất là không có nhiều hơn một hàm set-return trong cùng một SELECT
danh sách:
(Ngoài ra, biến thể cuối cùng thường nhanh nhất với một biên độ nhỏ.)
Tại sao timestamp [without time zone]
?
Có một số biến thể quá tải của generate_series()
. Hiện tại (Postgres 11):
SELECT oid::regprocedure AS function_signature
, prorettype::regtype AS return_type
FROM pg_proc
where proname = 'generate_series';
function_signature | return_type
: ------------------------------------------------- ------------------------------- | : --------------------------
create_series (số nguyên, số nguyên, số nguyên) | số nguyên
create_series (số nguyên, số nguyên) | số nguyên
create_series (bigint, bigint, bigint) | bigint
create_series (bigint, bigint) | bigint
create_series (số, số, số) | số
create_series (số, số) | số
create_series (dấu thời gian không có múi giờ, dấu thời gian không có múi giờ, khoảng thời gian) | dấu thời gian không có múi giờ
create_series (dấu thời gian với múi giờ, dấu thời gian với múi giờ, khoảng thời gian) | dấu thời gian với múi giờ
( numeric
các biến thể đã được thêm vào với Postgres 9.5.) Các biến thể liên quan là hai biến thể cuối cùng được in đậm và quay lại timestamp
/ timestamptz
.
Không có biến thể lấy hoặc trảdate
. Một diễn viên rõ ràng là cần thiết để trở lại date
. Lệnh gọi với các timestamp
đối số sẽ giải quyết trực tiếp đến biến thể tốt nhất mà không cần chuyển sang các quy tắc phân giải kiểu hàm và không cần ép kiểu bổ sung cho đầu vào.
timestamp '2004-03-07'
là hoàn toàn hợp lệ, btw. Phần thời gian bị bỏ qua được mặc định thành 00:00
với định dạng ISO.
Nhờ độ phân giải kiểu hàm mà chúng ta vẫn có thể vượt qua date
. Nhưng điều đó đòi hỏi nhiều công việc hơn từ Postgres. Có một dàn diễn viên ngầm từ date
đến timestamp
cũng như một từ date
đến timestamptz
. Sẽ không rõ ràng, nhưng timestamptz
được "ưu tiên" trong số "các loại ngày / giờ". Vì vậy trận đấu được quyết định ở bước 4d. :
Chạy qua tất cả các ứng cử viên và giữ những ứng cử viên chấp nhận các kiểu ưu tiên (thuộc loại kiểu của dữ liệu đầu vào) ở hầu hết các vị trí mà chuyển đổi kiểu sẽ được yêu cầu. Giữ tất cả các ứng cử viên nếu không ai chấp nhận các loại ưu tiên. Nếu chỉ còn lại một ứng cử viên, hãy sử dụng nó; khác tiếp tục bước tiếp theo.
Ngoài công việc bổ sung trong độ phân giải kiểu hàm, điều này còn bổ sung thêm một diễn viên timestamptz
- điều này không chỉ làm tăng thêm chi phí mà còn có thể gây ra các vấn đề với DST dẫn đến kết quả không mong muốn trong một số trường hợp hiếm hoi. (DST là một khái niệm mỉa mai, btw, không thể nhấn mạnh điều này đủ.)
Tôi đã thêm các bản trình diễn vào fiddle hiển thị kế hoạch truy vấn đắt tiền hơn:
db <> fiddle here
Có liên quan: