【问题标题】:How to restrict the upper limit of rows while doing join in SQL?SQL中join时如何限制行数上限?
【发布时间】: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 数据库。

【问题讨论】:

  • 你能添加想要的输出吗?有点混乱!
  • 我已经添加了。

标签: sql join 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 生成两个日期之间的月份。如果您想要每天的记录,这将是一个更清晰的查询,但我必须使用另一个子查询来获取每月级别的结果。

      【讨论】:

        猜你喜欢
        • 2010-10-04
        • 1970-01-01
        • 2016-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多