【问题标题】:Restructure query to group by month/year将查询重组为按月/年分组
【发布时间】:2014-03-31 17:43:08
【问题描述】:

我有一个数据库,其中包含数百万行信息,可在整个系统中跟踪订单的进度。从头到尾,一个订单可能会通过 2 到 20 个系统。此旅程的每个部分都将记录在数据库中,例如

ORDER ID        SOURCE        DESTINATION        TIMESTAMP
10               Sys 1          Sys 2            01-Jan-14
10               Sys 2          Sys 3            01-Jan-14
10               Sys 3          Sys 4            03-Jan-14
10               Sys 4          Sys 5            07-Jan-14

订单离开该系统时的时间戳记录。

我写了一个查询来确定每个订单的长度:

Select ORDERID, 1 + TRUNC(MAX(TIMESTAMP)) - TRUNC(MIN(TIMESTAMP))
from DATABASE GROUP BY ORDERID

这工作正常,对于上述订单将产生 7 天。当我对数据库中的 每个 元组运行此查询时,我会得到数据库中每个订单的平均端到端订单进度时间。然后,我可以使用所有这些单独的总计来找出总体平均订单时间。

这一切都很好,但我现在希望能够将其分解为单独的月/年配对,这样我就可以有效地查看给定月份系统中的平均时间长度是增加还是减少.

我对 SQL 相当缺乏经验,我真的不知道从哪里开始。我如何编写一个查询来跟踪任何订单的开始日期,并查看它在系统中的停留时间,从而产生系统中的总天数每月/年组合?

样本数据

目前,上面的查询会产生一系列像这样的元组:

Order Id    Days in System
0145240 1
10000   1
10001   1
10003   130
10004   3
10007   1
10008   13
10009   1
10010   1

然后我可以找到所有这些信息的平均值。我真正想要的是能够做这样的事情:

ORDER ID        SOURCE        DESTINATION        TIMESTAMP
10               Sys 1          Sys 2            01-Jan-14
10               Sys 2          Sys 3            01-Jan-14
10               Sys 3          Sys 4            03-Jan-14
10               Sys 4          Sys 5            07-Jan-14
11               Sys 1          Sys 2            01-Feb-14
11               Sys 2          Sys 3            03-Mar-14
12               Sys 1          Sys 2            04-Mar-14           
12               Sys 2          Ssy 3            05-Mar-14
13               Sys 1          Sys 2            07-Mar-14
13               Sys 2          Sys 3            14-Mar-14

想象一下以上都是完成的订单。

OrderID 10:从头到尾花了 7 天时间。
OrderID 11:从头到尾花了 31 天。
OrderID 12:从头到尾花了 2 天时间。
OrderID 13:从头到尾花了 8 天时间。

OrderId 10 是 1 月份的唯一订单,OrderID 11 是 2 月份唯一的订单,OrderID 12 和 13 都发生在 3 月份。因此,理想情况下,我要设计的查询会产生以下结果:

Jan 2014:    Average = 7
Feb 2014:    Average = 31
Mar 2014:    Average = 5 (i.e. (2 + 8) / 2)

【问题讨论】:

  • 您能否举一些简单的数据示例,以消除歧义。谢谢

标签: sql oracle-sqldeveloper


【解决方案1】:

按月计算

Select ORDERID, 
       to_char(to_date(Timestamp, 'DD-MM-YYYY'), 'Month'),
       1 + TRUNC(MAX(TIMESTAMP)) - TRUNC(MIN(TIMESTAMP)) as duration
from DATABASE GROUP BY ORDERID, to_char(to_date(Timestamp, 'DD-MM-YYYY'), 'Month')
Order By ORDERID,duration

同样,您可以从时间戳日期列中提取年份并按 orderid 和年份分组,以每年跟踪每个订单 ID 的持续时间。

【讨论】:

  • 您不需要to_date(timestamp, ...),如果您的 NLS_DATE_FORMAT 与DD-MON-YYYY 不匹配,确实会出错。
【解决方案2】:

您可以查看分析函数,但一种相当简单的方法是添加“开始”日期(这有点令人困惑,因为它似乎是订单离开时的时间戳第一个系统,而不是它到达那里的时候?):

select orderid, min(timestamp) as first_seen,
  1 + trunc(max(timestamp)) - trunc(min(timestamp)) as duration
from database
group by orderid
order by orderid;

一些额外的数据可能会给你:

   ORDERID FIRST_SEEN                     DURATION
---------- ---------------------------- ----------
        10 01-JAN-14 09.00.00.000000000          7 
        11 01-JAN-14 09.00.00.000000000          2 
        12 31-JAN-14 09.00.00.000000000          3 
        13 01-FEB-14 09.00.00.000000000          2 

然后,您可以将其用作子查询和平均值,方法是对“第一次看到”日期的月份的第一个日期进行分组:

select trunc(first_seen, 'MM') as month,
  avg(duration) as duration
from (
  select orderid, min(timestamp) as first_seen,
    1 + trunc(max(timestamp)) - trunc(min(timestamp)) as duration
  from database group by orderid
)
group by trunc(first_seen, 'MM')
order by trunc(first_seen, 'MM');

MONTH       DURATION
--------- ----------
01-JAN-14          4 
01-FEB-14          2 

SQL Fiddle.

将表称为“数据库”有点令人困惑,因为它是keyword(虽然不是保留的,所以它是合法的)。并且调用列“时间戳”也有点奇怪,特别是如果它实际上是 date 而不是 timestamp - 不清楚你的实际表有哪个。但是,由于您更改了发布名称,所以这是没有实际意义的。

with your expanded sample data:

   ORDERID FIRST_SEEN                     DURATION
---------- ---------------------------- ----------
        10 01-JAN-14 00.00.00.000000000          7 
        11 01-FEB-14 00.00.00.000000000         31 
        12 04-MAR-14 00.00.00.000000000          2 
        13 07-MAR-14 00.00.00.000000000          8 

MONTH       DURATION
--------- ----------
01-JAN-14          7 
01-FEB-14         31 
01-MAR-14          5 

【讨论】:

  • 感谢您提供这个绝妙的解决方案。仅供参考,我更改了所有内容的默认字段名称。它不是真的称为数据库或时间戳。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多