我有3个表格需要报告:
*dates* date_sk | full_date 1 | 2013-01-01 2 | 2013-02-01 3 | 2013-03-01 *person* person_sk | person_id | person_name 1 | 10 | John 2 | 11 | Bob 3 | 12 | Jill *person_portfolio* person_portfolio_sk | date_sk | person_sk | res_value | report_month 1 | 1 | 1 | 15 | 2013-01-01 2 | 1 | 2 | 10 | 2013-01-01 3 | 1 | 3 | 1 | 2013-01-01 4 | 2 | 1 | 30 | 2013-02-01
(想象一下'日期'表填写过去10年和未来10年的每个日期)
我一直在努力找出,为了使用日期范围进行比较报告,如何在该时间范围内没有任何条目替换该人的0值。这是我试过的查询:
SELECT
p.person_id,
COALESCE(pp.res_value,0)::NUMERIC(16,2) AS res_value,
pp.report_month
FROM person p
LEFT JOIN person_portfolio pp
ON p.person_sk = pp.person_sk
LEFT JOIN date d
ON d.date_sk = pp.date_sk
WHERE person_id IN ('10','11','12')
AND pp.report_month >= '2013-01-01' --From Date
AND pp.report_month <= '2013-05-01' -- To Date
AND d.day_number_of_month = 1
ORDER BY p.person_id DESC;
我想要返回的输出最终总共为15行。 3人x 5个月的数据=总共15行。我在日期表中遗漏了day_number_of_month列,但它保留了每月第一个的数字1,第二个的数字等等(每个月的每一天都在此表中)。它应该是这样的:
person_id | res_value | report_month 10 | 15 | 2013-01-01 10 | 30 | 2013-02-01 10 | 0 | 2013-03-01 10 | 0 | 2013-04-01 10 | 0 | 2013-05-01 11 | 10 | 2013-01-01 11 | 0 | 2013-02-01 11 | 0 | 2013-03-01 11 | 0 | 2013-04-01 11 | 0 | 2013-05-01 12 | 1 | 2013-01-01 12 | 0 | 2013-02-01 12 | 0 | 2013-03-01 12 | 0 | 2013-04-01 12 | 0 | 2013-05-01
但我只得到这些结果:
person_id | res_value | report_month 10 | 15 | 2013-01-01 10 | 30 | 2013-02-01 11 | 10 | 2013-01-01 12 | 1 | 2013-01-01
所以基本上......目前有一种可行的方法,当没有#report; report_month&#39;的条目时,我可以将0值行注入结果中。对于特定的人?我会感激任何形式的帮助,因为我已经为此工作了两个星期,现在试图完成这份报告。谢谢!
答案 0 :(得分:1)
您对输出的描述提供了有关如何解决问题的指导。首先使用cross join
生成行。然后引入其余的数据。
鉴于您的查询结构,我没有看到日期表的目的。如果我假设每个报告期至少有一份报告,我可以这样做:
SELECT p.person_id,
COALESCE(pp.res_value,0)::NUMERIC(16,2) AS res_value,
d.report_month
FROM (SELECT DISTINCT person_id FROM person p WHERE person_id IN ('10', '11', '12')
) p CROSS JOIN
(SELECT DISTINCT pp.report_month
FROM person_portfolio pp
WHERE pp.report_month >= '2013-01-01' AND
pp.report_month <= '2013-05-01'
) d LEFT JOIN
person_portfolio pp
ON p.person_sk = pp.person_sk and
d.report_month = pp.report_month
ORDER BY p.person_id DESC, d.report_month asc;
但是,您的数据并非如此。您可以生成日期。在您的环境中,我不知道使用generate_series()
或date
表是否更好。在任何情况下,这将替换上面的d
子查询与具有所有感兴趣日期的子查询。
答案 1 :(得分:0)
查找“OUTER JOIN”..
未经测试,但您可以尝试这样的事情吗? (从您的日期表开始,将日期范围限制在您想要的范围内,然后开始将它们连接到您的其他表格... OUTER JOIN说“即使您在此日期找不到包含数据的人,请保留日期..我想看到它)
SELECT
p.person_id,
COALESCE(pp.res_value,0)::NUMERIC(16,2) AS res_value,
pp.report_month
FROM date d
LEFT OUTER JOIN person p
ON d.date_sk = p.date_sk
LEFT OUTER JOIN person_portfolio pp
ON p.person_sk = pp.person_sk
WHERE person_id IN ('10','11','12')
AND d.date_sk >= '2013-01-01' --From Date
AND d.date_sk <= '2013-05-01' -- To Date
ORDER BY p.person_id DESC;