如何在sql中的表中按组填充缺少的日期

时间:2013-09-29 06:20:44

标签: sql date loops

我想知道如何使用循环来填充缺省日期,其值为零,基于sql中组的开始/结束日期,以便我在每个组中都有连续的时间序列。我有两个问题。

  1. 如何为每个组循环?
  2. 如何使用每个组的开始/结束日期来动态填写缺少的日期?
  3. 我的输入和预期输出如下所示。

    输入:我有一张表A,如

    date     value      grp_no
    8/06/12    1         1
    8/08/12    1         1
    8/09/12    0         1
    8/07/12    2         2
    8/08/12    1         2
    8/12/12    3         2
    

    此外,我还有一张表B,可用于与A联系以填补缺少的日期。

    date
    ...
    8/05/12
    8/06/12
    8/07/12
    8/08/12
    8/09/12
    8/10/12
    8/11/12
    8/12/12
    8/13/12
    ...
    

    如何使用A和B在sql中生成以下输出?

    输出:

    date     value      grp_no
    8/06/12    1         1  
    8/07/12    0         1
    8/08/12    1         1
    8/09/12    0         1
    8/07/12    2         2
    8/08/12    1         2
    8/09/12    0         2
    8/10/12    0         2
    8/11/12    0         2
    8/12/12    3         2
    

    请将您的代码和建议发给我。非常感谢你提前!!!

3 个答案:

答案 0 :(得分:12)

你可以这样做,没有循环

SELECT p.date, COALESCE(a.value, 0) value, p.grp_no
  FROM
(
  SELECT grp_no, date
    FROM
  (
    SELECT grp_no, MIN(date) min_date, MAX(date) max_date
      FROM tableA
     GROUP BY grp_no
  ) q CROSS JOIN tableb b 
   WHERE b.date BETWEEN q.min_date AND q.max_date
) p LEFT JOIN TableA a
    ON p.grp_no = a.grp_no 
   AND p.date = a.date

最里面的子查询每组抓取最小和最大日期。然后与TableB交叉连接,在每组的最小 - 最大范围内生成所有可能的日期。最后,外部选择使用TableA的外部联接,并使用value填充0列,以填充TableA中缺少的日期。

输出:

|       DATE | VALUE | GRP_NO |
|------------|-------|--------|
| 2012-08-06 |     1 |      1 |
| 2012-08-07 |     0 |      1 |
| 2012-08-08 |     1 |      1 |
| 2012-08-09 |     0 |      1 |
| 2012-08-07 |     2 |      2 |
| 2012-08-08 |     1 |      2 |
| 2012-08-09 |     0 |      2 |
| 2012-08-10 |     0 |      2 |
| 2012-08-11 |     0 |      2 |
| 2012-08-12 |     3 |      2 |

这是 SQLFiddle 演示

答案 1 :(得分:0)

以下查询对uniontableA执行tableB。然后,它使用分组依据合并来自tableAtableB的行,以便将来自tableB的所有日期都包含在结果中。如果日期不在tableA中,则该行的valuegrp_no具有0。否则,该行将具有valuegrp_no的实际值。

select
   dat,
   sum(val),
   sum(grp)
from
   (
      select
         date as dat,
         value as val,
         grp_no as grp
      from
         tableA
   union
      select
         date,
         0,
         0
      from
         tableB
      where
         date >= date '2012-08-06' and
         date <= date '2012-08-13'
   )
group by
   dat
order by
   dat

如果发现此查询对我来说更容易理解。它也运行得更快。这需要16秒,而类似的right join查询则需要32秒。

此解决方案仅适用于数字数据。

此解决方案假定使用固定的日期范围。通过一些额外的工作,可以将该查询修改为将日期范围限制为tableA中的内容。

答案 2 :(得分:0)

我只需要查询返回我想要的时间段内的所有日期。没有连接。我想我会与那些想要将它们放在您的查询中的人分享。只需将 365 更改为您想要的任何时间范围即可。

DECLARE @s DATE = GETDATE()-365, @e DATE = GETDATE();
SELECT TOP (DATEDIFF(DAY, @s, @e)+1)
 DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY number)-1, @s)
 FROM [master].dbo.spt_values
 WHERE [type] = N'P' ORDER BY number