Gener_series cho nhiều loại bản ghi trong postgresql


8

Tôi có hai bảng mà tôi muốn truy vấn: pest_countspestsnó trông giống như:

CREATE TABLE pests(id,name)
AS VALUES
  (1,'Thrip'),
  (2,'Fungus Gnosts');

CREATE TABLE pest_counts(id,pest_id,date,count)
AS VALUES
  (1,1,'2015-01-01'::date,14),
  (2,2,'2015-01-02'::date,5);

Tôi muốn sử dụng postgres ' generate_seriesđể hiển thị số lượng từng loại dịch hại được tìm thấy trong chuỗi ngày:

kết quả mong đợi

name         | date       | count
-------------+------------+-------
Thrip        | 2015-01-01 | 14
Thrip        | 2015-01-02 | 0
....
Fungus Gnats | 2015-01-01 | 0
Fungus Gnats | 2015-01-02 | 5
...

Tôi biết tôi sẽ cần một cái gì đó như sau nhưng tôi không chắc chắn làm thế nào để làm phần còn lại:

SELECT date FROM generate_series('2015-01-01'::date, '2015-12-31'::date, '1 day') date

Câu trả lời:


8

Tôi thường giải quyết các vấn đề như vậy bằng cách thiết lập một bảng cho tất cả các điểm dữ liệu có thể (ở đây là các loài gây hại và ngày). Điều này có thể dễ dàng đạt được bởi một CROSS JOIN, xem WITHtruy vấn dưới đây.

Sau đó, là bước hoàn thiện, tôi chỉ (ngoài) tham gia các phép đo hiện có, dựa trên ID dịch hại và ngày - tùy chọn đưa ra mặc định cho các giá trị bị thiếu thông qua COALESCE().

Vì vậy, toàn bộ truy vấn là:

WITH data_points AS (
    SELECT id, name, i::date
    FROM pests
    CROSS JOIN generate_series('2015-01-01'::date, '2015-01-05', '1 day') t(i)
) 
SELECT d.name, d.i, COALESCE(p.cnt, 0) 
FROM data_points AS d 
LEFT JOIN pest_counts AS p 
    ON d.id = p.pest_id 
    AND d.i = p.count_date;

Kiểm tra nó tại nơi làm việc trên SQLFiddle .

Lưu ý: khi (các) bảng hoặc CROSS JOINsê-ri được tạo lớn, thực hiện bên trong CTE có thể là một ý tưởng tồi. (Nó phải cụ thể hóa tất cả các hàng, bất kể có dữ liệu cho một ngày nhất định hay không). Trong trường hợp này, người ta nên làm tương tự trong FROMmệnh đề, như là một tham gia phụ được ngoặc đơn thay vì tham chiếu hiện tại data_points. Bằng cách này, người lập kế hoạch hiểu rõ hơn về các hàng bị ảnh hưởng và khả năng sử dụng các chỉ mục. Tôi sử dụng CTE trong ví dụ vì nó trông sạch hơn vì lợi ích của ví dụ.


0

Tôi sẽ đề nghị lần sau bạn sử dụng fiddle.com để có một lược đồ trực tuyến để chơi.

Hàm Gener_series trả về một bộ dấu thời gian, vì vậy bạn sẽ cần truyền nó đến ngày bên ngoài hàm. Điều này là cần thiết trong truy vấn hiện tại vì timestampsẽ không khớp với datetrong pest_countsbảng.

sandbox=# \df generate_series
   Schema   |      Name       |         Result data type          |                        Argument data types                         |  Type  
(...)
 pg_catalog | generate_series | SETOF timestamp without time zone | timestamp without time zone, timestamp without time zone, interval | normal
 pg_catalog | generate_series | SETOF timestamp with time zone    | timestamp with time zone, timestamp with time zone, interval       | normal
(6 rows)

Tôi sẽ đề xuất một cái gì đó như:

SELECT p.name, pc.date, pc.count 
FROM generate_series('2015-01-01'::date, '2015-12-31'::date, '1 day') days 
join pest_counts pc ON (days::date = pc.date) 
join pests p ON (p.id = pc.pest_id) ;
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.