SQL中join时如何限制行数上限?
Posted
技术标签:
【中文标题】SQL中join时如何限制行数上限?【英文标题】:How to restrict the upper limit of rows while doing join in SQL? 【发布时间】:2017-06-29 18:07:59 【问题描述】:我有两张表:余额和日历。
余额:
账户日期余额 1111 2014 年 1 月 1 日 100 1111 2014 年 2 月 1 日 156 1111 03/01/2014 300 1111 04/01/2014 300 1111 07/01/2014 468 1112 2014 年 2 月 1 日 300 1112 03/01/2014 300 1112 06/01/2014 300 1112 2014 年 7 月 1 日 350 1112 08/01/2014 400 1112 09/01/2014 450 1113 2014 年 1 月 1 日 30 1113 2014 年 2 月 1 日 40 1113 2014 年 3 月 1 日 45 1113 06/01/2014 45 1113 2014 年 7 月 1 日 60 1113 2014 年 8 月 1 日 50 1113 2014 年 9 月 1 日 20 1113 10/01/2014 10日历
日期 business_day_ind 2014 年 1 月 1 日 2014 年 2 月 1 日 2014 年 3 月 1 日 2014 年 4 月 1 日 2014 年 5 月 1 日 06/01/2014 是 2014 年 7 月 1 日 2014 年 8 月 1 日 2014 年 9 月 1 日 2014 年 10 月 1 日我需要做以下事情:
我需要填写所有帐户的缺失天数,直到它具有价值的最大天数。假设账户 1111,它的价值只到 2014 年 7 月 1 日,所以只需要填写日期。但是当我加入日历表(普通左加入)时,我无法将最大天数限制为帐户可用的日期。 1111 01/01/2014 100 N 1111 2014 年 2 月 1 日 156 是 1111 03/01/2014 300 是 1111 04/01/2014 300 是 1111 2014 年 5 月 1 日 1111 06/01/2014 1111 07/01/2014 468 是 1111 08/01/2014 是 1111 09/01/2014 是 1111 2014 年 10 月 1 日 1112 2014 年 1 月 1 日 1112 2014 年 2 月 1 日 300 是 1112 03/01/2014 300 是 1112 2014 年 4 月 1 日 1112 2014 年 5 月 1 日 1112 06/01/2014 300 是 1112 07/01/2014 350 是 1112 08/01/2014 400 是 1112 09/01/2014 450 是 1112 2014 年 10 月 1 日我需要一种有效的方法(最好不涉及多个步骤)将日期限制为帐户的最大可用余额日期(07/01/2014 在 1111 的情况下,09/01/2014 的情况下在 1112 的情况下)
期望的输出:
1111 01/01/2014 100 N 1111 2014 年 2 月 1 日 156 是 1111 03/01/2014 300 是 1111 04/01/2014 300 是 1111 2014 年 5 月 1 日 1111 06/01/2014 1111 07/01/2014 468 是 1112 2014 年 1 月 1 日 1112 2014 年 2 月 1 日 300 是 1112 03/01/2014 300 是 1112 2014 年 4 月 1 日 1112 2014 年 5 月 1 日 1112 06/01/2014 300 是 1112 07/01/2014 350 是 1112 08/01/2014 400 是 1112 09/01/2014 450 是在填补缺失天数后,我打算将前一个工作日的余额归入缺失天数。我计划获取每个日期的前一个工作日,并通过以 acct 和前一个工作日为键加入原始余额表来更新丢失的行。
谢谢。
我是 Greenplum 数据库。
【问题讨论】:
你能添加想要的输出吗?有点混乱! 我已经添加了。 【参考方案1】:一种可能的方法是在子查询中放置第二个选择。例如:
select ... from calendar a left outer join balance b on a.date = b.date
where a.date <= (select max(date) from balance c where b.Account = c.Account )
【讨论】:
【参考方案2】:我想你有第三张桌子,accounts
:
select
accounts.account,
calendar.date,
balance.balance,
calendar.business_day_ind
from
accounts cross join lateral (
select *
from calendar
where calendar.date <= (
select max(date)
from balance
where balance.account = accounts.account)) as calendar left join
balance on (balance.account = accounts.account and balance.date = calendar.date)
order by
accounts.account, calendar.date;
About lateral joins
【讨论】:
【参考方案3】:这是一个有趣的挑战!
CREATE TABLE balance
(account int, balance_date timestamp, balance int)
DISTRIBUTED BY (account, balance_date);
INSERT INTO balance
values (1111,'01/01/2014', 100),
(1111, '02/01/2014', 156),
(1111, '03/01/2014', 300),
(1111, '04/01/2014', 300),
(1111, '07/01/2014', 468),
(1112, '02/01/2014', 300),
(1112, '03/01/2014', 300),
(1112, '06/01/2014', 300),
(1112, '07/01/2014', 350),
(1112, '08/01/2014', 400),
(1112, '09/01/2014', 450),
(1113, '01/01/2014', 30),
(1113, '02/01/2014', 40),
(1113, '03/01/2014', 45),
(1113, '06/01/2014', 45),
(1113, '07/01/2014', 60),
(1113, '08/01/2014', 50),
(1113, '09/01/2014', 20),
(1113, '10/01/2014', 10);
CREATE TABLE calendar
(calendar_date timestamp, business_day_ind boolean)
DISTRIBUTED BY (calendar_date);
INSERT INTO calendar
values ('01/01/2014', false),
('02/01/2014', true),
('03/01/2014', true),
('04/01/2014', false),
('05/01/2014', false),
('06/01/2014', true),
('07/01/2014', true),
('08/01/2014', true),
('09/01/2014', true),
('10/01/2014', true);
analyze balance;
analyze calendar;
现在是查询。
select d.account, d.my_date, b.balance, c.business_day_ind
from (
select account, start_date + interval '1 month' * (generate_series(0, duration)) AS my_date
from (
select account, start_date, (date_part('year', duration) * 12 + date_part('month', duration))::int as duration
from (
select start_date, age(end_date, start_date) as duration, account
from (
select account, min(balance_date) as start_date, max(balance_date) as end_date
from balance
group by account
) as sub1
) as sub2
) sub3
) as d
left outer join balance b on d.account = b.account and d.my_date = b.balance_date
join calendar c on c.calendar_date = d.my_date
order by d.account, d.my_date;
结果:
account | my_date | balance | business_day_ind
---------+---------------------+---------+------------------
1111 | 2014-01-01 00:00:00 | 100 | f
1111 | 2014-02-01 00:00:00 | 156 | t
1111 | 2014-03-01 00:00:00 | 300 | t
1111 | 2014-04-01 00:00:00 | 300 | f
1111 | 2014-05-01 00:00:00 | | f
1111 | 2014-06-01 00:00:00 | | t
1111 | 2014-07-01 00:00:00 | 468 | t
1112 | 2014-02-01 00:00:00 | 300 | t
1112 | 2014-03-01 00:00:00 | 300 | t
1112 | 2014-04-01 00:00:00 | | f
1112 | 2014-05-01 00:00:00 | | f
1112 | 2014-06-01 00:00:00 | 300 | t
1112 | 2014-07-01 00:00:00 | 350 | t
1112 | 2014-08-01 00:00:00 | 400 | t
1112 | 2014-09-01 00:00:00 | 450 | t
1113 | 2014-01-01 00:00:00 | 30 | f
1113 | 2014-02-01 00:00:00 | 40 | t
1113 | 2014-03-01 00:00:00 | 45 | t
1113 | 2014-04-01 00:00:00 | | f
1113 | 2014-05-01 00:00:00 | | f
1113 | 2014-06-01 00:00:00 | 45 | t
1113 | 2014-07-01 00:00:00 | 60 | t
1113 | 2014-08-01 00:00:00 | 50 | t
1113 | 2014-09-01 00:00:00 | 20 | t
1113 | 2014-10-01 00:00:00 | 10 | t
(25 rows)
我必须获取每个帐户的最小和最大日期,然后使用 generate_series 生成两个日期之间的月份。如果您想要每天的记录,这将是一个更清晰的查询,但我必须使用另一个子查询来获取每月级别的结果。
【讨论】:
以上是关于SQL中join时如何限制行数上限?的主要内容,如果未能解决你的问题,请参考以下文章