【问题标题】:To get weekly record with subtotal for date range spanning over two years in Oracle SQL在 Oracle SQL 中获取跨越两年的日期范围小计的每周记录
【发布时间】:2015-06-16 07:14:23
【问题描述】:

根据要求,我需要生成给定期间的每周报告。如果期间是同一年,则以下查询可以正常工作,但如果年份跨越两年,则同样失败。因为当年的开始周日期是从上一年开始的,这会导致记录的顺序出现问题。

电流输出

WEEK    DAY    FCB_ID     QUANTITY_ORDERS
1   12/29/2014  1935    1
1   12/30/2014  1935    1
1   12/31/2014  1935    1
1   1/1/2015    1935    1
1   1/2/2015    1935    1
1   1/3/2015    1935    1
1   1/4/2015    1935    1
1                1      7
2   1/5/2015    1935    1
2   1/6/2015    1935    1
2   1/7/2015    1935    1
2   1/8/2015    1935    1
2   1/9/2015    1935    1
2   1/10/2015   1935    1
2   1/11/2015   1935    1
2                  1    7
3   1/12/2015   1935    1
3   1/13/2015   1935    2
3   1/14/2015   1935    3
3   1/15/2015   1935    3
3                1      9
51  12/15/2014  1935    1
51  12/16/2014  1935    1
51  12/17/2014  1935    1
51  12/18/2014  1935    1
51  12/19/2014  1935    1
51  12/20/2014  1935    1
51  12/21/2014  1935    1
51               1      7
52  12/22/2014  1935    1
52  12/23/2014  1935    1
52  12/24/2014  1935    1
52  12/25/2014  1935    1
52  12/26/2014  1935    1
52  12/27/2014  1935    1
52  12/28/2014  1935    1
52              1       37

预期结果 上一年的 desc 和当年的 asc 的周数

51  12/15/2014  1935    1
51  12/16/2014  1935    1
51  12/17/2014  1935    1
51  12/18/2014  1935    1
51  12/19/2014  1935    1
51  12/20/2014  1935    1
51  12/21/2014  1935    1
51               1      7
52  12/22/2014  1935    1
52  12/23/2014  1935    1
52  12/24/2014  1935    1
52  12/25/2014  1935    1
52  12/26/2014  1935    1
52  12/27/2014  1935    1
52  12/28/2014  1935    1
1   12/29/2014  1935    1
1   12/30/2014  1935    1
1   12/31/2014  1935    1
1   1/1/2015    1935    1
1   1/2/2015    1935    1
1   1/3/2015    1935    1
1   1/4/2015    1935    1
1                1      7
2   1/5/2015    1935    1
2   1/6/2015    1935    1
2   1/7/2015    1935    1
2   1/8/2015    1935    1
2   1/9/2015    1935    1
2   1/10/2015   1935    1
2   1/11/2015   1935    1
2                  1    7
3   1/12/2015   1935    1
3   1/13/2015   1935    2
3   1/14/2015   1935    3
3   1/15/2015   1935    3
3                1      9
3                1      37

查询详情

SELECT * FROM(
SELECT to_char(to_date(day),'IW') as Week, day as Day, NVL(fcb_id,1) as FCB_ID,sum(Quantity_Orders)Quantity_Orders

FROM
(
SELECT 
day, fcb_id, mo_number, count(DISTINCT mo_number) Quantity_Orders

FROM report_table
WHERE fcb_id = '1111'  
AND day >=  TRUNC(to_date('12/15/2014', 'MM/DD/YYYY'))  --[SD]
AND day <=  TRUNC(to_date('1/15/2015', 'MM/DD/YYYY'))  --[ED]
GROUP BY day, fcb_id, mo_number
ORDER BY fcb_id, day, mo_number
)
GROUP BY ROLLUP(to_char(to_date(DAY),'IW'), day, fcb_id)
ORDER BY to_char(to_date(DAY),'IW'), day, fcb_id
)
WHERE  (FCB_ID = 1 AND DAY IS NULL) OR (FCB_ID != 1); -- this condition is used to remove extra row generated after each day due to DAY field in Rollup function

【问题讨论】:

  • 您必须在 GROUP BY 中添加年份。
  • 改用to_char(to_date(day),'IYYYYIW')
  • to_date(day) 的使用是一个错误。日期列已经是 DATE 格式,因此您依赖于使用默认 nls_date_format 设置完成的额外隐式转换将其截断为一天,或者您没有明确指定格式掩码并再次依赖默认 nls_date_format 设置。如果这些应该发生变化,那么宾果游戏!错误...

标签: sql oracle


【解决方案1】:

注意:在精彩评论后编辑。

如果我理解的话,该解决方案只会影响“order by”子句。您必须在 order by 中包含年份(iso 年份)。

但是您的查询有一个危险的错误。 Oracle(和大多数 RDBMS)只保证最外层选择的顺序(内层选择顺序不保证)。 你的外部查询是:

SELECT * FROM (...) WHERE  (FCB_ID = 1 AND DAY IS NULL) OR (FCB_ID != 1)

它没有顺序子句。两个 order 子句都在内部查询中,因此在所有情况下都不能保证 order。

通常,为了避免错误,您必须在外部选择中包含 order by 子句(并且不需要内部“order by”),但在这种情况下,它可能会干扰 ROLLUP 函数。

所以我们要去掉外部的选择,将外部的 WHERE 条件转化为内部的 HAVING 条件(这样 ROLLUP 和 ORDER BY 可以看到相同的数据)。

然后下一个问题是如何知道汇总小计中的年份。 我们在 rollup 第一个参数中添加 iso-year 来解决这个问题:

ROLLUP(to_char(to_date(DAY),'IYYYIW'), day, fcb_id)

并让 SELECT 子句提取星期并删除年份(使用 SUBSTRING)。

在 ROLLUP 中包含年份不影响组和小计的创建,它允许 ORDER BY 知道年份,最后 SELECT 子句将其消除。

注意,不要使用这个:

SELECT to_char(to_date(day),'IW') as Week,...

因为 oracle 无法识别 to_char(to_date(day),'IW') 是一个 group by 表达式。您必须在 ROLLUP 的第一个参数上使用 SUBSTR。

SELECT SUBSTR(to_char(to_date(day),'IYYYIW'),5) as Week,...

所以最后的查询是:

SELECT SUBSTR(to_char(to_date(day),'IYYYIW'),5) as Week, day as Day, NVL(fcb_id,1) as FCB_ID,sum(Quantity_Orders)Quantity_Orders

FROM
(
SELECT 
day, fcb_id, mo_number, count(DISTINCT mo_number) Quantity_Orders

FROM report_table
WHERE fcb_id = '1111'  
AND day >=  TRUNC(to_date('12/15/2014', 'MM/DD/YYYY'))  --[SD]
AND day <=  TRUNC(to_date('1/15/2015', 'MM/DD/YYYY'))  --[ED]
GROUP BY day, fcb_id, mo_number
)
GROUP BY ROLLUP(to_char(to_date(DAY),'IYYYIW'), day, fcb_id)
HAVING  (NVL(fcb_id,1) = 1 AND DAY IS NULL) OR (NVL(fcb_id,1) != 1)
ORDER BY to_char(to_date(DAY),'IYYYIW'), day, fcb_id;

【讨论】:

  • 大家好,谢谢回复。由于小计为空值,建议的更改不起作用,这使得所有带有小计的记录排在最后。有人可以建议替代方法,用于小计每周数据,并保持前一年较旧一周的顺序。
  • 在以 iso 格式给出年份后查询正在运行。
  • @Ravish 当我用您的第一条评论编辑答案时,您的第二条评论出现了。所以也许你现在不需要答案。很高兴知道您已经解决了问题。
猜你喜欢
  • 2015-12-03
  • 2011-12-18
  • 1970-01-01
  • 1970-01-01
  • 2015-01-31
  • 1970-01-01
  • 2021-08-21
  • 2019-03-18
  • 1970-01-01
相关资源
最近更新 更多