crosstab()
hàm có hai tham số.
Nên hoạt động như thế này, để nhận các giá trị cho năm 2012:
SELECT * FROM crosstab(
$$SELECT testname, to_char(last_update, 'mon_YYYY'), count(*)::int AS ct
FROM tests
WHERE current_status = 'FAILED'
AND last_update >= '2012-01-01 0:0'
AND last_update < '2013-01-01 0:0' -- proper date range!
GROUP BY 1,2
ORDER BY 1,2$$
,$$VALUES
('jan_2012'::text), ('feb_2012'), ('mar_2012')
, ('apr_2012'), ('may_2012'), ('jun_2012')
, ('jul_2012'), ('aug_2012'), ('sep_2012')
, ('oct_2012'), ('nov_2012'), ('dec_2012')$$)
AS ct (testname text
, jan_2012 int, feb_2012 int, mar_2012 int
, apr_2012 int, may_2012 int, jun_2012 int
, jul_2012 int, aug_2012 int, sep_2012 int
, oct_2012 int, nov_2012 int, dec_2012 int);
Tìm lời giải thích chi tiết trong câu hỏi có liên quan này.
Tôi đã không kiểm tra. Như @Craig đã nhận xét, các giá trị mẫu sẽ hữu ích.
Đã được kiểm tra ngay bây giờ với trường hợp thử nghiệm của riêng tôi.
Không hiển thị giá trị NULL
Vấn đề chính (những tháng không có hàng sẽ không hiển thị) được ngăn chặn bởi crosstab()
hàm với hai tham số.
Bạn không thể sử dụng COALESCE
trong truy vấn bên trong, vì NULL
các giá trị được chèn bởi crosstab()
chính nó. Bạn có thể ...
1. Gói toàn bộ nội dung vào một truy vấn con:
SELECT testname
,COALESCE(jan_2012, 0) AS jan_2012
,COALESCE(feb_2012, 0) AS feb_2012
,COALESCE(mar_2012, 0) AS mar_2012
, ...
FROM (
-- query from above)
) x;
2. LEFT JOIN
truy vấn chính cho danh sách đầy đủ các tháng.
Trong trường hợp này, bạn không cần tham số thứ hai theo định nghĩa.
Đối với phạm vi lớn hơn, bạn có thể sử dụng generate_series()
để tạo các giá trị.
SELECT * FROM crosstab(
$$SELECT t.testname, m.mon, count(x.testname)::int AS ct
FROM (
VALUES
('jan_2012'::text), ('feb_2012'), ('mar_2012')
,('apr_2012'), ('may_2012'), ('jun_2012')
,('jul_2012'), ('aug_2012'), ('sep_2012')
,('oct_2012'), ('nov_2012'), ('dec_2012')
) m(mon)
CROSS JOIN (SELECT DISTINCT testname FROM tests) t
LEFT JOIN (
SELECT testname
,to_char(last_update, 'mon_YYYY') AS mon
FROM tests
WHERE current_status = 'FAILED'
AND last_update >= '2012-01-01 0:0'
AND last_update < '2013-01-01 0:0' -- proper date range!
) x USING (mon)
GROUP BY 1,2
ORDER BY 1,2$$
)
AS ct (testname text
, jan_2012 int, feb_2012 int, mar_2012 int
, apr_2012 int, may_2012 int, jun_2012 int
, jul_2012 int, aug_2012 int, sep_2012 int
, oct_2012 int, nov_2012 int, dec_2012 int);
Trường hợp thử nghiệm với dữ liệu mẫu
Đây là một trường hợp thử nghiệm với một số dữ liệu mẫu mà OP không cung cấp được. Tôi đã sử dụng cái này để kiểm tra và làm cho nó hoạt động.
CREATE TEMP TABLE tests (
id bigserial PRIMARY KEY
,testname text NOT NULL
,last_update timestamp without time zone NOT NULL DEFAULT now()
,current_status text NOT NULL
);
INSERT INTO tests (testname, last_update, current_status)
VALUES
('foo', '2012-12-05 21:01', 'FAILED')
,('foo', '2012-12-05 21:01', 'FAILED')
,('foo', '2012-11-05 21:01', 'FAILED')
,('bar', '2012-02-05 21:01', 'FAILED')
,('bar', '2012-02-05 21:01', 'FAILED')
,('bar', '2012-03-05 21:01', 'FAILED')
,('bar', '2012-04-05 21:01', 'FAILED')
,('bar', '2012-05-05 21:01', 'FAILED');