SQL查询中间流程步骤

时间:2014-01-31 21:08:22

标签: sql sql-server

我有一个事实表,每行代表这些关键信息

  • 序列号
  • 活动类型(装运,退货,索赔)
  • 活动日期
  • 帐户名称

一个连续剧在其生命中可以有很多事件。例如

  1. 发货至 _
  2. _
  3. 返回
  4. 发货至 _
  5. 来自 _
  6. 的声明
  7. _
  8. 返回
  9. 来自 _
  10. 的声明
  11. 发货至 _
  12. 来自 _
  13. 的声明

    这里的挑战是我需要根据先前的交易检查每个实例是否是有效的交易。例如:

    • 只有与上次发货的帐户匹配时,退货才有效
    • 索赔仅在尚未退回并且索赔与上次发货的帐户匹配时才有效。

    已经能够做到的是创建该序列的最新发货事件报告。基本上忽略了其他一切。

    我无法弄清楚的是,我将如何创建一份全年报告,以便在一年中记录所有可能的违规行为。请记住,我需要运行此报告的数千个序列号。

    换句话说,使用上面的示例,我可以轻松地将#8识别为有效/无效,但我如何创建一个也说明#4和#6状态的报告?然后为每个序列执行此操作。我确信这类问题经常出现,但我无法找到类似问题的资源。

2 个答案:

答案 0 :(得分:2)

我喜欢这种有趣的,听起来像我的商业用户的要求,这就是我要做的。为了执行类似的规则,我使用了LEADLAG分析函数。下面是演示如何使用它们。只需弄清楚规则是什么,然后使用LAGLEAD

将其写出来

LEAD - http://technet.microsoft.com/en-us/library/hh213125.aspx

LAG - http://technet.microsoft.com/en-us/library/hh231256.aspx

DECLARE @MyTable AS TABLE
    (
     SerialNumber BIGINT
    ,ActivityType VARCHAR(25)
    ,ActivityDate DATETIME
    ,AccountName VARCHAR(100)
    )

INSERT INTO @MyTable VALUES(1,'SHIP','01/01/2013','Bill');
INSERT INTO @MyTable VALUES(2,'RETURN','01/02/2013','Bill');
INSERT INTO @MyTable VALUES(3,'SHIP','01/03/2013','Bill');
INSERT INTO @MyTable VALUES(4,'RETURN','01/01/2013','Joe');
INSERT INTO @MyTable VALUES(5,'SHIP','01/02/2013','Joe');
INSERT INTO @MyTable VALUES(6,'SHIP','01/01/2013','James');
INSERT INTO @MyTable VALUES(7,'SHIP','01/02/2013','James');
INSERT INTO @MyTable VALUES(8,'SHIP','01/02/2013','Bill');

SELECT *
,CASE WHEN LAG(ActivityType) OVER (PARTITION BY AccountName ORDER BY ActivityDate ASC) IS NULL AND ActivityType IN ('Return','Claim') THEN 'FAIL' ELSE 'PASS' END AS Rule1
,CASE WHEN LAG(ActivityType) OVER (PARTITION BY AccountName ORDER BY ActivityDate ASC) IN ('Return','Claim') AND ActivityType IN ('Return','Claim') THEN 'FAIL' ELSE 'PASS' END AS Rule2
,CASE WHEN LAG(ActivityType) OVER (PARTITION BY AccountName ORDER BY ActivityDate ASC) = 'SHIP' AND ActivityType IN ('Return','Claim') THEN 'PASS' ELSE 'FAIL' END AS Rule3
,CASE WHEN LAG(ActivityType) OVER (PARTITION BY AccountName ORDER BY ActivityDate ASC) = 'SHIP' AND ActivityType = 'SHIP' THEN 'FAIL' ELSE 'PASS' END AS Rule4
FROM @MyTable
ORDER BY AccountName, ActivityDate

规则1检查以确定退货和索赔仅在发货后发生,如果它是发生该规则失败的第一个项目。

Rule2检查以确保Return和Claim不会在彼此之后发生。

规则3更多的是验证正确顺序发生退货和索赔的良好记录。

规则4是为了防止两次运送到同一帐户。

答案 1 :(得分:1)

这是解决问题的逻辑。

您将向每条记录追加上次装运的帐户和最后返回的帐户。这些是逻辑所需的值。

获得这些有点复杂。首先,查询为每个装运/返回的行分配1。然后它执行累积求和,以获得具有相同"最近发送/返回"的行。然后在行内,它将分配帐户。

毕竟,逻辑应该很简单。这是:

select f.*
from (select f.*, max(AccountName) over (partition by Serial, ShippedGroup) as LastShippedAccount,
             max(AccountName) over (partition by Serial, ReturnedGroup) as LastReturnedGroup
      from (select f.*,
                   sum(case when ActivityName = 'Shipped' then 1 else 0 end) over (partition by Serial
                                                                                   order by ActivityDate
                                                                                  ) as ShippedGroup,
                   sum(case when ActivityName = 'Returned' then 1 else 0 end) over (partition by Serial
                                                                                  order by ActivityDate
                                                                                 ) as ReturnedGroup,
            from fact f
           ) f
     ) f
where not (ActivityName = 'Return' and ActivityAccount = LastShippedAccount) or
      not (ActivityName = 'Claim' and ActivityAccount = LastShippedAccount and ActivityAccount <> LastReturnedAccount);