Oracle:选择日期范围内缺少值的日期的值

Posted

技术标签:

【中文标题】Oracle:选择日期范围内缺少值的日期的值【英文标题】:Oracle: Select values in date range with days where value is missing 【发布时间】:2012-06-08 09:20:01 【问题描述】:

我想从范围内的表中选择值。 像这样的:

SELECT
  date_values.date_from,
  date_values.date_to,
  sum(values.value)
FROM values
  inner join date_values on values.id_date = date_values.id
  inner join date_units on date_values.id_unit = date_units.id
WHERE
  date_values.date_from >= '14.1.2012' AND
  date_values.date_to <= '30.1.2012' AND
  date_units.id = 4
GROUP BY
  date_values.date_from,
  date_values.date_to
ORDER BY
  date_values.date_from,
  date_values.date_to;

但是这个查询只给我返回天的范围,任何值在哪里。像这样:

14.01.12    15.01.12    66
15.01.12    16.01.12    4
17.01.12    18.01.12    8
...etc

(这里缺少 16.01.12 到 17.01.12)

但我也想选择缺失值,像这样:

14.01.12    15.01.12    66
15.01.12    16.01.12    4
16.01.12    17.01.12    0
17.01.12    18.01.12    8
...etc

我不能使用 PL/SQL,如果您能建议更通用的解决方案,我可以将其扩展到小时、月、年;会很棒的。

【问题讨论】:

在我看来你需要一个外连接。日期 16.01.12 到 17.01.12 似乎在 date_units 表中没有相应的记录。我说的对吗? date_values 表中缺少日期 16.01.12 到 17.01.12。 Date_units 是表,我在其中存储范围类型(​​如天(date_units.id = 4)、小时、月、周、年......)。我认为,我“只是”需要生成第二个临时日期表并与这两个表相交。问题是如何生成这个表? 【参考方案1】:

我假设您提供的是 date_fromdate_to。如果是这样,您可以先生成日期列表,然后加入它以获得剩余的结果。或者,您可以 union 对您的 date_values 表进行此查询,因为 union 会执行不同的操作,这将删除任何额外的数据。

如果这是日期列表的生成方式:

 select to_date('14.1.2012','dd.mm.yyyy') + level - 1 as date_from
      , to_date('14.1.2012','dd.mm.yyyy') + level as date_to
   from dual
connect by level <= to_date('30.1.2012','dd.mm.yyyy') 
                  - to_date('14.1.2012','dd.mm.yyyy')

您的查询可能会变成

with the_dates as (
 select to_date('14.1.2012','dd.mm.yyyy') + level - 1 as date_from
      , to_date('14.1.2012','dd.mm.yyyy') + level as date_to
   from dual
connect by level <= to_date('30.1.2012','dd.mm.yyyy') 
                  - to_date('14.1.2012','dd.mm.yyyy')
         )
SELECT
  dv.date_from,
  dv.date_to,
  sum(values.value)
FROM values
  inner join ( select the_dates.date_from, the_dates.date_to, date_values.id
                 from the_dates
                 left outer join date_values
                   on the_dates.date_from = date_values.date_from ) dv
     on values.id_date = dv.id
  inner join date_units on date_values.id_unit = date_units.id
WHERE
  date_units.id = 4
GROUP BY
  dv.date_from,
  dv.date_to
ORDER BY
  dv.date_from,
  dv.date_to;

with 语法被称为子查询分解,在这种情况下并不真正需要,但它使代码更简洁。

我还假设date_values 中的date 列是日期。当您进行字符串比较时,这并不明显。您应始终明确转换为适用的日期,并且应始终将日期存储为日期。从长远来看,它可以省去很多麻烦,因为不会出现输入错误或比较错误的情况。

【讨论】:

以上是关于Oracle:选择日期范围内缺少值的日期的值的主要内容,如果未能解决你的问题,请参考以下文章

计算按日期范围拆分的值的先前出现次数

在oracle中怎么判断一个日期是不是在一定时间范围内

mysql在日期范围内选择日期[重复]

按日期范围选择数据并换行

在一个范围内选择最大和最小日期时间

子查询返回超过 1 个值 - 使用特定日期的值更新日期范围内的记录