2013-07-23 3 views
0

Я хочу вернуть результирующий набор, который возвращает дату вступления в силу и дату окончания действия для идентификатора с несколькими изменениями поставщика. Для этого я просматриваю таблицу транзакций, в которой записываются идентификатор, идентификатор поставщика и дата начала транзакции. В случаях, когда идентификатор переключил поставщиков, я хочу уйти в отставку старой ассоциации и записать новую ассоциацию. Мое намерение состоит в том, чтобы вставить новую строку с последней датой переключения в качестве начальной даты вступления в силу и null в качестве конечной даты вступления в силу. Чтобы завершить событие, я хочу обновить последнюю предыдущую строку с датой окончания действия, заполненной последней датой переключения. В случаях, когда у меня есть транзакция, но идентификатор не переключил поставщиков, я хочу игнорировать строку.SQL: Не удалось вернуть эффективные даты начала и окончания по порядку по разделу по разделу

У меня есть работа для одного идентификатора, однако, когда я добавляю второй идентификатор, порядок/разбиение не работает.

Вот сценарий для генерации тестовых строк. Отмечается 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; 

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

EDITED

Вот желаемые результаты:

enter image description here

+0

В вашем примере имеется только 'select'. Однако вы говорите, что хотите сделать «вставку» и «обновление». Что значит «работает» для одного идентификатора? Можете ли вы привести пример ожидаемого результата для данных, которые вы предоставляете? –

+0

@ Gordon Linoff, вы правы - я не добавлял вставки/обновления только для удобства просмотра инструкции select, которая по существу способствовала бы обеим действиям. – plditallo

ответ

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 
0

Все, что вы имели необходимо было изменить линию в sifted CTE на это:

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

Примечание lcard, добавлено в раздел.

Все заявление будет выглядеть следующим образом:

;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.OrgSplit + 1 = b.OrgSplit порядка по a.lcard, a.suppId

Как только я увидел перепутали lcard комбинации suppId я знал, где эта проблема была

+0

, мы получаем тот же набор результатов, что и 70082,506,2013-06-23, нуль правильный - 2 записи для 700382,49401 должны быть сокращены до 1: 700382,49401,2013-03-15,2013 -06-23. – plditallo

+0

... и ... 832019 следует уменьшить до 2--832019,27088,2013-06-23, null и 832019,232,2013-05-16,2013-06-23. – plditallo

+0

спасибо за это. – plditallo