25

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

  1. 如何为每个组循环?
  2. 如何使用每个组的开始/结束日期来动态填写缺失的日期?

我的输入和预期输出如下所示。

输入:我有一张桌子 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

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

4

3 回答 3

36

你可以这样做没有循环

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列。0TableA

输出:

| 日期 | 价值 | 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演示

于 2013-09-29T06:54:50.053 回答
1

以下查询执行unionwithtableAtableB。然后它使用 group by 来合并行tableAtableB以便所有日期tableB都在结果中。如果日期不在 中tableA,则该行具有 0valuegrp_novalue否则,该行具有和的实际值grp_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.

于 2020-06-16T18:00:20.887 回答
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
于 2021-04-09T11:39:07.620 回答