0

我想带回一个结果集,该结果集返回具有多个供应商更改的 id 的开始生效日期和结束生效日期。为此,我正在查看一个交易表,其中记录了 id、供应商的 id 和交易发生的日期。在id切换供应商的情况下,我想退出旧的关联并记录新的关联。我的意图是插入一个新行,其中最新的切换日期作为开始生效日期,空值作为结束生效日期。为了完成该活动,我想用最新的切换日期填充的结束生效日期更新上一行。在我有交易但 id 没有切换供应商的情况下,我想忽略该行。

我对单个 id 有效,但是,当我添加第二个 id 时,顺序/分区不起作用。

这是生成测试行的脚本。记录了适用于单个 id 的 sql。

    -- Note: use this to emulate the known switched suppliers table

    create table #switched
    (lcard bigint);

    insert into #switched (lcard) values (700382)
    insert into #switched (lcard) values (832019)

    select * from #switched

    -- Note: this temp data represents a previously grouped/partitioned table
            --       prepped for this next phase of action

    create table #PartitionTest 
    (   FauxId int,
        lcard bigint,
        suppId int,
        switchDate datetime
    );


    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (1,700382,506,cast('Jun 23 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (2,700382,49401,cast('May 22 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (3,700382,49401,cast('May  4 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (4,700382,49401,cast('May  2 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (5,700382,49401,cast('Apr 26 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (6,700382,49401,cast('Mar 15 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (1,832019,27088,cast('Jun 18 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (2,832019,232,cast('May 24 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (3,832019,232,cast('May 23 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (4,832019,232,cast('May 22 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (5,832019,232,cast('May 21 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (6,832019,232,cast('May 17 2013 12:00AM' as datetime))
    INSERT INTO #PartitionTest (FauxId,lcard,suppId,switchDate) VALUES (7,832019,232,cast('May 16 2013 12:00AM' as datetime))

    -- Note: Order results by lcard, then order the supplier id by
        --       the transaction date found. FauxId is from the previous partitioning

    select * from #PartitionTest
     order by lcard,fauxId, suppId, switchDate

    -- This is the statement that is failing when attempting to utilize 
        -- the ids in #switched as the criterion processing sets of ids.

    ;with sifted
        as ( select *,
          row_number() over (ORDER BY switchDate) - row_number() over (PARTITION BY suppId ORDER BY switchDate) as G
        from #PartitionTest
        where lcard in
         (select lcard
            from #switched
          )
         -- // DEBUG TEST: specific card holder(s)
         -- NOTE: when both lcards are used, the beginEffDate/endEffDate goal fails
         -- and lcard in ('8320198','7003824')
         -- NOTE: this represents the intent
         and lcard in ('832019')
        ),
       refined as
         (select lcard,
                 suppId,
                MIN(switchDate) BeginEffDate,
                ROW_NUMBER() OVER (ORDER BY min(switchDate)) as OrgSplit
         from sifted
          group by lcard,suppId, G)
   select a.lcard,
          a.suppId,
          a.BeginEffDate,
          b.BeginEffDate as EndEffDate
    from refined a
          left join refined b
            on a.OrgSplit + 1 = b.OrgSplit
    order by a.lcard, a.suppId



    -- drop table #switched;
    -- drop table #PartitionTest;

==================================================== =================

已编辑

以下是期望的结果:

在此处输入图像描述

4

2 回答 2

0

您所要做的就是将siftedCTE 中的一行更改为:

      row_number() over (ORDER BY switchDate) - row_number() over (PARTITION BY lcard, suppId ORDER BY switchDate) as G

注释lcard,添加到 PARTITION BY。

整个语句将如下所示:

;with sifted
    as ( select *,
      row_number() over (ORDER BY switchDate) - row_number() over (PARTITION BY lcard, suppId ORDER BY switchDate) as G
    from #PartitionTest
    where lcard in
     (select lcard
        from #switched
      )
     -- // DEBUG TEST: specific card holder(s)
     -- NOTE: when both lcards are used, the beginEffDate/endEffDate goal fails
     -- and lcard in ('8320198','7003824')
     -- NOTE: this represents the intent
     and lcard in (832019,700382)
    ),
   refined as
     (select lcard,
             suppId,
            MIN(switchDate) BeginEffDate,
            ROW_NUMBER() OVER (ORDER BY min(switchDate)) as OrgSplit
     from sifted
      group by lcard,suppId, G)

选择 a.lcard, a.suppId, a.BeginEffDate, b.BeginEffDate 作为 EndEffDate 从提炼 a 左连接提炼 b on a.OrgSplit + 1 = b.OrgSplit order by a.lcard, a.suppId

当我看到混合的 lcard、suppId 组合时,我就知道问题出在哪里

于 2013-07-23T02:07:56.800 回答
0

在 SQL Server 2012 中,我使用了 dense_rank() 选项,而不是使用 partition/over。解决方案:

    WITH R AS (
    SELECT
        lcard,
        suppId,
        switchDate,
        DENSE_RANK() OVER(PARTITION BY lcard ORDER BY switchDate) -
        DENSE_RANK() OVER(PARTITION BY lcard ORDER BY suppId, switchDate) AS grp
    FROM
        #PartitionTest
    ),
    S AS (
    SELECT
        lcard,
        suppId,
        MAX(switchDate) AS dt,
        ROW_NUMBER() OVER(PARTITION BY lcard ORDER BY MAX(switchDate)) AS rn
    FROM
        R
    GROUP BY
        lcard,
        suppId,
        grp
    )
    SELECT
        A.lcard,
        A.suppId,
        A.dt AS BeginEffDate,
        B.dt AS EndEffDate
    FROM
        S AS A
        LEFT OUTER JOIN
        S AS B
        ON A.lcard = B.lcard
        AND A.rn = B.rn - 1
    ORDER BY
        lcard,
        BeginEffDate
    GO
于 2013-07-23T19:56:49.647 回答