计算从一种状态到另一种状态需要多少天:SQL

Posted

技术标签:

【中文标题】计算从一种状态到另一种状态需要多少天:SQL【英文标题】:Work out how many days it took from one status to another : SQL 【发布时间】:2014-11-06 09:50:18 【问题描述】:

请尽情欣赏我们数据库的当前结构。

我们的 DBA 目前要离开两周,我的 SQL 知识非常有限,我喜欢留在 UI 和中间层。

我们要弄清楚的是如何执行以下操作,我们需要编写一个查询来计算所有佣金从“已验证”过渡到“已支付”的平均时间(以天为单位)经销商,目前状态为

    已创建 已验证 拒绝 等待付款 付费 已退款

我认为这个查询需要直接针对佣金历史表?

由于我对 SQL 的了解有限,我不确定如何编写这样的查询...

任何帮助都会很棒。

【问题讨论】:

以可以复制的格式添加一堆样本数据(比如 10-15 行),以及您认为的输出应该是什么。此外,可以退还某些东西的事实是否会影响您希望在输出中显示的内容,因为这些内容将不再被支付? 您的状态 1-6 是否在 NewPaymentStatusId 中保持? @Tanner 是的,如果退款了,状态将是 1-6,那么理想情况下我们不会担心它,我们会在某个时候将其扩展为一个日期范围。 【参考方案1】:

这是一种实现您所追求的方法,尽管它可能不是最有效的。在我看来,它更像是您希望运行的一次性查询,而不是您要频繁运行以影响数据库性能的查询。

测试台设置:

CREATE TABLE Commission
(
    CommissionId INT,
    DealerId INT
)

CREATE TABLE CommissionHistory
(
    CommissionId INT,
    ActionDate DATETIME,
    NewPaymentStatusId INT
)

插入虚拟数据 - 1 个经销商的 5 个佣金:

INSERT INTO dbo.Commission
        ( CommissionId ,
          DealerId
        )
VALUES ( 1 , 1 ),
       ( 2 , 1 ),
       ( 3 , 1 ),
       ( 4 , 1 ),
       ( 5 , 1 ),

INSERT INTO dbo.CommissionHistory
        ( CommissionId ,
          ActionDate ,
          NewPaymentStatusId
        )
VALUES ( 1 , GETDATE() -25, 1 ),
       ( 1 , GETDATE() -21, 2 ),
       ( 1 , GETDATE() -18, 3 ),
       ( 1 , GETDATE() -16, 4 ),
       ( 1 , GETDATE() -5, 5 ),
       ( 2 , GETDATE() -10, 1 ),
       ( 2 , GETDATE() -9, 2 ),
       ( 2 , GETDATE() -8, 3 ),
       ( 2 , GETDATE() -7, 4 ),
       ( 2 , GETDATE() -6, 5 ),
       ( 3 , GETDATE() -10, 1 ),
       ( 3 , GETDATE() -8, 2 ),
       ( 3 , GETDATE() -6, 3 ),
       ( 3 , GETDATE() -4, 4 ),
       ( 3 , GETDATE() -2, 5 ),
       ( 3 , GETDATE() -25, 6 ),
       ( 4 , GETDATE() -10, 1 ),
       ( 4 , GETDATE() -7, 2 ),
       ( 4 , GETDATE() -6, 3 ),
       ( 4 , GETDATE() -4, 4 ),
       ( 4 , GETDATE() -1, 5 ),
       ( 5 , GETDATE() -1, 1 ),
       ( 5 , GETDATE() -1, 2 )

因此,对于虚拟数据,佣金 1、2 和 4 被归类为有效记录,因为它们的状态为 2 和 5。3 被排除在外,因为它已退还,5 被排除在外,因为它没有被支付。

为了生成平均值,我编写了以下查询:

-- set the required dealer id
DECLARE @DealerId INT = 1

-- return all CommissionId's in to a temp table that have statuses 2 and 5, but not 6
SELECT DISTINCT CommissionId
INTO #DealerCommissions
FROM dbo.CommissionHistory t1      
WHERE CommissionId IN (SELECT CommissionId 
                       FROM dbo.Commission 
                       WHERE    DealerId = @DealerId)
AND NOT EXISTS (SELECT CommissionId 
                FROM dbo.CommissionHistory t2 
                WHERE t2.NewPaymentStatusId = 6 AND t2.CommissionId = t1.CommissionId)
AND EXISTS (SELECT CommissionId 
            FROM dbo.CommissionHistory t2 
            WHERE t2.NewPaymentStatusId = 2 AND t2.CommissionId = t1.CommissionId)
AND EXISTS (SELECT CommissionId 
            FROM dbo.CommissionHistory t2 
            WHERE t2.NewPaymentStatusId = 5 AND t2.CommissionId = t1.CommissionId)

-- use the temp table to return average difference between the MIN & MAX date
;WITH cte AS (
    SELECT CommissionId FROM #DealerCommissions
)
SELECT  AVG(CAST(DaysToCompletion AS DECIMAL(10,8)))
FROM    (
         SELECT DATEDIFF(DAY, MIN(ch.ActionDate), MAX(ch.ActionDate)) DaysToCompletion
         FROM cte
         INNER JOIN dbo.CommissionHistory ch ON ch.CommissionId = cte.CommissionId
         GROUP BY ch.CommissionId
) AS averageDays

-- remove temp table
DROP TABLE #DealerCommissions

【讨论】:

【参考方案2】:

对于历史表中的每个佣金,您可以获得最大验证日期和最小支付日期,假设支付日期总是晚于验证日期。然后您可以加入佣金表,按经销商 ID 分组,以获取平均持续时间(以天为单位)。

with comm as(
select 
    commissionid,
    max(case NewPamentStatus when 'Verified' then ActionDate else null end) as verified_date,  
    min(case NewPamentStatus when 'Paid' then ActionDate else null end) as paid_date
        --using max or min just incase that same status will be recorded more than one time.
from 
    CommissionHistory
group by 
    commistionid
)
select 
    c.DealerId,
    avg(datediff(day,comm.verified_date,comm.paid_date))
from
    comm
inner join
    commission c
on  c.commissionid = comm.commissionid
where 
    datediff(day,comm.verified_date,comm.paid_date)>0
    -- to get rid off the commissions with paid date before the verified date or in same day
group by
    c.DealerId

【讨论】:

以上是关于计算从一种状态到另一种状态需要多少天:SQL的主要内容,如果未能解决你的问题,请参考以下文章

如何为 UIControl/UIButton 动画从一种状态到另一种状态的过渡? [复制]

JavaScript对象状态

Oracle PL/SQL 和 Shell 脚本:从一种模式到另一种模式

oracle学习9

Altova DatabaseSpy:将整个数据库结构从一种数据库类型迁移到另一种数据库类型

数据库事务