【问题标题】:Oracle SQL: How to show empty weeks / weeks without data?Oracle SQL:如何在没有数据的情况下显示空周/周?
【发布时间】:2012-06-30 12:47:05
【问题描述】:

类似于this question,但我的数据集有一个包含许多 ID 的附加列。每个 ID 都有一个按固定时间范围回溯的数据集,并且某些周可能缺少数据 - 我想填写缺失周的值。

例如,我想要这个:

ID      WEEKEND_DAY     VALUE
A00     2012-01-01      1
A00     2012-01-08      7
B00     2012-01-08      4
B00     2012-01-15      3

扩展至此:

ID      WEEKEND_DAY     VALUE
A00     2012-01-01      1
A00     2012-01-08      7
A00     2012-01-15      0
B00     2012-01-01      0
B00     2012-01-08      4
B00     2012-01-15      3

我已经有一个已知的 WEEKEND_DAY 范围(在上述情况下,每周从 2012 年 1 月 1 日到 2012 年 1 月 15 日)我想填写。我该怎么做?

【问题讨论】:

  • 您是否想要缺少一周,即使那一周的表格中没有任何内容?
  • @TonyHopkinson 是的,我愿意 - 虽然我的数据集理论上不应该发生。
  • 在 postgres 中有一个名为 generate_series 的函数,可以用来生成一个包含所有星期的控制表。我没有详细研究这个,但可能会有所帮助......spatialdbadvisor.com/oracle_spatial_tips_tricks/82/…
  • @samyi 获得几周的系列不是问题(我正在使用 SELECT rownum FROM dual CONNECT BY level

标签: sql oracle date group-by


【解决方案1】:

假设您只需要每个ID 每周都在场,这非常简单。

首先,如果您还没有“日历表”,我建议您使用它。这应该包括一周的“结束”列(或至少,您想要选择的星期几)。这当然可以使用递归 CTE 动态生成,但无论如何,永久的都是有用的。

鉴于您的原始表格:

WITH id_by_date (id, weekend) as (
                 SELECT a.id, b.actualDate
                 FROM (SELECT DISTINCT id
                       FROM original) a  -- or use a table that only has ids
                 CROSS JOIN (SELECT actualDate
                             FROM calendar
                             WHERE isWeekend = '1') b) -- or dayOfWeek = 7
SELECT a.id, a.weekend, COALESCE(b.value, 0)
FROM id_by_date a
LEFT JOIN original b
ON b.id = a.id
AND b.weekend_day = a.weekend
ORDER BY a.id, a.weekend

【讨论】:

  • 这不是有效的 Oracle 语法。
  • @jonearles:也许,不是 Oracle 版本支持这种语法,所以你可能是对的。不过,据我所知,这应该在最新版本中工作。
  • 抱歉,我已经习惯了 DB2(而且我已经离开了我的实例)。虽然我认为这是(相当)标准语法。
  • 我无法理解其他人发现了哪些特殊问题,但现在我明白了。一方面,它们都是微不足道的。在表和子选择之后,除一个之外的所有内容都与as 相关:Oracle 只是不喜欢它,所以不是original as b,而只是original b,不是... from (select ...) as a,而只是... from (select ...) a 等。另一个问题是右括号的位置不正确:where isWeekend = '1')) as b 应该是 where is Weekend = '1') b)(即别名应该移动到前一个括号之前的位置)。
  • @AndriyM - 啊,感谢您指出as 的问题。不过,CTE 中别名的错位是我自己的错。
【解决方案2】:

使用partitioned outer join

select data.id, weeks.weekend_day, nvl(value, 0) value
from
(
    select date '2012-01-01' weekend_day from dual union all
    select date '2012-01-08' weekend_day from dual union all
    select date '2012-01-15' weekend_day from dual
) weeks
left join
(
    select 'A00' id, date '2012-01-01' weekend_day, 1 value from dual union all
    select 'A00' id, date '2012-01-08' weekend_day, 7 value from dual union all
    select 'B00' id, date '2012-01-08' weekend_day, 4 value from dual union all
    select 'B00' id, date '2012-01-15' weekend_day, 3 value from dual
) data
    partition by (data.id)
    on weeks.weekend_day = data.weekend_day

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 2014-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多