多个州之间的天数差异
Posted
技术标签:
【中文标题】多个州之间的天数差异【英文标题】:Difference in days between multiple states 【发布时间】:2018-07-30 14:28:34 【问题描述】:我正在使用 ORACLE SQL,但遇到了一个难以解决的问题。
在我的系统中用户可以订购产品。这些订单可以处于不同的状态:WAITING
、ACCEPTED
、IN_PROGRESS
、DELIVERED
、REMOVED
、DELETED
。
这些订单记录在一个名为 tblorderlog 的表中。
该表包含以下列:OrderId
、OrderState
和 OrderStateDate
。
我想找出OrderStateDates
之间的天数差异,但问题是并非每个订单都经过每个订单状态,因此一个订单可能只来自WAITING
、DELIVERED
和REMOVED
。
无论州的顺序如何,有没有办法计算州之间的天数?
我做了什么:
select distinct susu.orderid, ol.orderstatedate, ol.orderstate,
case
when ol.orderstate = 'WAITING' then null
when ol.orderstate = 'ACCEPTED' then round(tblaccepted.orderstatedate-
tblwaiting,0)
when ol.orderstate = 'IN_PROGRESS' then round(tblinprogress.orderstatedate-tblaccepted.orderstatedate,0)
when ol.orderstate = 'DELIVERED' then round(tbldelivered.orderstatedate-tblinprogress.orderstatedate,0)
when ol.orderstate = 'REMOVED' then round(tblremoved.orderstatedate-tbldelivered.orderstatedate,0)
when ol.orderstate = 'DELETED' then round(tbldeleted.orderstatedate-tblremoved.orderstatedate,0)
else -10 --(Random number)
end as days_between_orderstates
from tblsusu susu
left join tblorderlog ol on susu.orderid = ol.orderid
left join (select ol.orderid, ol.orderstatedate
from tblorderlog ol
where ol.orderstate = 'WAITING') tblwaiting on susu.orderid = tblwaiting.orderid
left join (select ol.orderid, ol.orderstatedate
from tblorderlog ol
where ol.orderstate = 'ACCEPTED') tblaccepted on susu.orderid = tblaccepted.orderid
left join (select ol.orderid, ol.orderstatedate
from tblorderlog ol
where ol.orderstate = 'IN_PROGRESS') tblinprogress on susu.orderid = tblinprogress.orderid
left join (select ol.orderid, ol.orderstatedate
from tblorderlog ol
where ol.orderstate = 'DELIVERED') tbldelivered on susu.orderid = tbldelivered.orderid
left join (select ol.orderid, ol.orderstatedate
from tblorderlog ol
where ol.orderstate = 'REMOVED') tblremoved on susu.orderid = tblremoved.orderid
left join (select ol.orderid, ol.orderstatedate
from tblorderlog ol
where ol.orderstate = 'DELETED') tbldeleted on susu.orderid = tbldeleted.orderid
order by susu.orderid, ol.orderstatedate
我想要这样的输出:
orderid orderstate orderdate days_between_order_states
21 WAITING 22/07/18 NULL (or empty)
21 ACCPETED 24/07/18 2
21 DELIVERED 25/07/18 1
21 REMOVED 25/07/18 0
21 DELETED 26/07/18 1
25 WAITING 01/08/18 NULL (or empty)
25 DELIVERED 05/08/18 4
25 DELETED 06/08/18 1
..
..
【问题讨论】:
状态可以按任何顺序排列,不只是有些可以跳过?它们可以重复吗?请在您的问题中包含一些具有代表性的示例数据和预期结果(作为格式化文本,而不是图像)。 您绝对不需要对同一个表 (tblorderlog
) 进行那么多左连接,只需添加一个,在您的案例表达式中,您可以将其别名与 orderstate
列一起使用。
@JorgeCampos,你能举个例子吗?
当您按照@AlexPoole 的要求在问题中添加信息时,我可以。
@AlexPoole 感谢您的编辑,我在这里有点新。但这是预期的输出
【参考方案1】:
如果您真的只是在寻找每个订单状态以及自前一个状态以来的天数,不管是什么,那么您并没有真正关注每个状态值 - 您只关注状态更改的顺序。
您可以使用lag()
分析函数来查看前一行,您可以在其中定义over()
子句中“上一个”的含义;在这里,您需要具有最近状态更改日期的相同订单 ID 的行。
作为起点,您可以查看以下内容:
select susu.orderid, ol.orderstatedate, ol.orderstate,
lag(ol.orderstatedate)
over (partition by susu.orderid order by ol.orderstatedate) as prev_orderstatedate,
lag(ol.orderstate)
over (partition by susu.orderid order by ol.orderstatedate) as prev_orderstate,
round(ol.orderstatedate - lag(ol.orderstatedate)
over (partition by susu.orderid order by ol.orderstatedate))
as days_between_orderstates
from tblsusu susu
join tblorderlog ol on ol.orderid = susu.orderid
order by susu.orderid, ol.orderstatedate;
对于每个订单日志条目,它将显示该状态及其日期;以及通过lag()
找到的先前状态和日期;并将计算当前时间和以前时间之间的差异。
根据您添加到问题的输出,并从中推断出原始数据并作为两个 CTE 提供(并跳过您不想要的 prev_
值):
with tblsusu (orderid) as (
select 21 from dual
union all select 25 from dual
), tblorderlog (orderid, orderstate, orderstatedate) as (
select 21, 'WAITING', date '2018-07-22' from dual
union all select 21, 'ACCPETED', date '2018-07-24' from dual
union all select 21, 'DELIVERED', date '2018-07-25' from dual
union all select 21, 'REMOVED', date '2018-07-25' from dual
union all select 21, 'DELETED', date '2018-07-26' from dual
union all select 25, 'WAITING', date '2018-08-01' from dual
union all select 25, 'DELIVERED', date '2018-08-05' from dual
union all select 25, 'DELETED', date '2018-08-06' from dual
)
select susu.orderid, ol.orderstatedate, ol.orderstate,
round(ol.orderstatedate - lag(ol.orderstatedate)
over (partition by susu.orderid order by ol.orderstatedate))
as days_between_orderstates
from tblsusu susu
join tblorderlog ol on ol.orderid = susu.orderid
order by susu.orderid, ol.orderstatedate;
ORDERID ORDERSTATE ORDERSTATE DAYS_BETWEEN_ORDERSTATES
---------- ---------- ---------- ------------------------
21 2018-07-22 WAITING
21 2018-07-24 ACCPETED 2
21 2018-07-25 DELIVERED 1
21 2018-07-25 REMOVED 0
21 2018-07-26 DELETED 1
25 2018-08-01 WAITING
25 2018-08-05 DELIVERED 4
25 2018-08-06 DELETED 1
如果除了来自tblsusu
的订单 ID 之外,您没有获得任何列,您甚至可能不需要表之间的连接,因为无论如何这在两个表中都存在。
【讨论】:
以上是关于多个州之间的天数差异的主要内容,如果未能解决你的问题,请参考以下文章