2017-07-27 55 views
0

我遇到了一個問題,關於在表中缺少令我頭痛的行。在一個序列中排序行並填充缺失行的空位

作爲基礎數據,我有以下表:

declare @table table 
(
    id1 int, 
    id2 int, 
    ch char(1) not null, 
    val int  
) 

insert into @table values (1112, 121, 'A', 12) 
insert into @table values (1351, 121, 'A', 13) 
insert into @table values (1411, 121, 'B', 81) 
insert into @table values (1312, 7, 'C', 107) 
insert into @table values (1401, 2, 'A', 107) 
insert into @table values (1454, 2, 'D', 107) 
insert into @table values (1257, 6, 'A', 1) 
insert into @table values (1269, 6, 'B', 12) 
insert into @table values (1335, 6, 'C', 12) 
insert into @table values (1341, 6, 'D', 5) 
insert into @table values (1380, 6, 'A', 3) 

輸出應該由ID2進行排序,並按照ch的固定順序,應該重複進行,直到下一個ID2開始。

順序:

'A' 
'B' 
'C' 
'D' 

如果順序或者圖案中斷,它應與空填補缺失的行,讓我得到這個結果表:

id1  id2  ch  val 
----------------------------  
1112 121  'A' 12 
NULL 121  'B' NULL 
NULL 121  'C' NULL 
NULL 121  'D' NULL 
1351 121  'A' 13 
1411 121  'B' 81 
NULL 121  'C' NULL 
NULL 121  'D' NULL 
NULL 7  'A' NULL 
NULL 7  'B' NULL 
1312 7  'C' 107 
NULL 7  'D' NULL 
1401 2  'A' 107 
NULL 2  'B' NULL 
NULL 2  'C' NULL 
1454 2  'D' 107 

等。 ..

我在找的是一種不用迭代就能做到的方法。

我希望有人能幫助!

在此先感謝!

回答

1

一個解決方案可能是這樣的:

declare @table table ( id1 int, id2 int, ch char(1) not null, val int ) 
insert into @table values (1112, 121, 'A', 12) 
    ,(1351, 121, 'A', 13),(1411, 121, 'B', 81),(1312, 7, 'C', 107),(1401, 2, 'A', 107) 
    ,(1454, 2, 'D', 107),(1257, 6, 'A', 1),(1269, 6, 'B', 12),(1335, 6, 'C', 12) 
    ,(1341, 6, 'D', 5),(1380, 6, 'A', 3) 
;with foo as 
(select 
    * 
    ,row_number() over (partition by id2 order by id1) rwn 
    ,ascii(isnull(lag(ch,1) over (partition by id2 order by id1),'A'))-ascii('A') prev 
    ,count(*) over (partition by id2,ch) nr 
    ,ascii(ch)-ascii('A') cur 
from @table 

) 
,bar as 
(
select 
*,case when cur<=prev and rwn>1 then 4 else 0 end + cur-prev step 
from foo 
) 
,foobar as 
(
select *,sum(step) over (partition by id2 order by id1 rows unbounded preceding) rownum 
from bar 
) 
,iterations as 
(
select id2,max(nr) nr from foo 
group by id2 
) 
,blanks as 
(
select 
id2,ch chnr,char(ch+ascii('A'))ch,ROW_NUMBER() over (partition by id2 order by c.nr,ch)-1 rownum,c.nr 
from iterations a 
inner join (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) c(nr) 
on c.nr<=a.nr 
cross join (values (0),(1),(2),(3)) b(ch) 
) 
select 
b.id1,a.id2,a.ch,b.val 
from blanks a 
left join foobar b 
on a.id2=b.id2 and a.rownum=b.rownum 
order by a.id2,a.rownum 

我首先讓查詢「foo」查看行號並獲取每個id2的ch的前一個值。

「bar」然後找出行之間有多少缺失值。例如,如果前一個是A並且當前是c,則有2個。如果前一個是A並且當前是A,那麼有4個!

「foobar」然後添加步驟,從而編號原始行,它們應該在最終輸出中。

「迭代次數」計算「ABCD」行應出現的次數。

「空白」,然後是所有的最後行,即每個ID2,它輸出的ROWNUM

最後我離開了加入所有的「ABCD」行,應該在最終輸出和數字他們「 foob​​ar「與id2和rownum上的」BLANKS「。因此我們得到了正確的行數,並且輸出了原始值中的值。

+0

非常感謝您的解答和解釋!你是個天才! –

0

我一點你的輸出混淆,試試這個:

更新

DECLARE @table TABLE 
    (
     row INT IDENTITY(1, 1) , 
     id1 INT , 
     id2 INT , 
     ch CHAR(1) NOT NULL , 
     val INT 
    ); 

DECLARE @Sequence TABLE (ch3 CHAR(1) NOT NULL); 


INSERT INTO @Sequence 
VALUES ('A'); 
INSERT INTO @Sequence 
VALUES ('B'); 
INSERT INTO @Sequence 
VALUES ('C'); 
INSERT INTO @Sequence 
VALUES ('D'); 

INSERT INTO @table 
VALUES (1112, 121, 'A', 12); 
INSERT INTO @table 
VALUES (1351, 121, 'A', 13); 
INSERT INTO @table 
VALUES (1411, 121, 'B', 81); 
INSERT INTO @table 
VALUES (1312, 7, 'C', 107); 
INSERT INTO @table 
VALUES (1401, 2, 'A', 107); 
INSERT INTO @table 
VALUES (1454, 2, 'D', 107); 
INSERT INTO @table 
VALUES (1257, 6, 'A', 1); 
INSERT INTO @table 
VALUES (1269, 6, 'B', 12); 
INSERT INTO @table 
VALUES (1335, 6, 'C', 12); 
INSERT INTO @table 
VALUES (1341, 6, 'D', 5); 
INSERT INTO @table 
VALUES (1380, 6, 'A', 3); 




SELECT r.id1 , 
     fin.id2 , 
     ch3 , 
     r.val 
FROM (SELECT * 
      FROM  (SELECT CASE WHEN r.chd - l.chd = 1 THEN 0 
            ELSE 1 
           END [gap in sq] , 
           l.* 
         FROM  (SELECT id2 , 
              ASCII(ch) chd , 
              ch , 
              val , 
              id1 , 
              row 
            FROM  @table 
           ) AS l 
           LEFT JOIN (SELECT id2 , 
                ASCII(ch) chd , 
                row 
              FROM @table 
             ) AS r ON l.row = r.row - 1 
        ) AS temp , 
        @Sequence s 
      WHERE  temp.[gap in sq] = 1 
        OR (temp.[gap in sq] = 0 
         AND s.ch3 = temp.ch 
         ) 
     ) AS fin 
     LEFT JOIN @table r ON r.id2 = fin.id2 
           AND r.id1 = fin.id1 
           AND r.ch = fin.ch3 
+0

非常感謝!但是1351和1411的順序是一樣的。因此,1411應該在1351行之後在第6行而不是第10行 –

0

如果你能夠在你的餐桌,它定義添加一個額外的列,其[ID2]從部分相同的序列,你可以試試這個:

declare @table table 
(
    id1 int, 
    id2 int, 
    ch char(1) not null, 
    val int, 
    category int -- extra column 
) 

insert into @table values (1112, 121, 'A', 12, 1) 
insert into @table values (1351, 121, 'A', 13, 2) 
insert into @table values (1411, 121, 'B', 81, 2) 
insert into @table values (1312, 7, 'C', 107, 3) 
insert into @table values (1401, 2, 'A', 107, 4) 
insert into @table values (1454, 2, 'D', 107, 4) 
insert into @table values (1257, 6, 'A', 1, 5) 
insert into @table values (1269, 6, 'B', 12, 5) 
insert into @table values (1335, 6, 'C', 12, 5) 
insert into @table values (1341, 6, 'D', 5, 5) 
insert into @table values (1380, 6, 'A', 3, 5) 


DECLARE @sequence table (seq varchar(1)) 
INSERT INTO @sequence values ('A'), ('B'), ('C'), ('D') 


SELECT b.id1, a.id2, a.seq, b.val, a.category 
INTO #T1 
FROM (
    SELECT * 
    FROM @table 
    CROSS JOIN @sequence 
) A 
LEFT JOIN (
    SELECT * FROM @table 
) B 
    ON 1=1 
    AND a.id1 = b.id1 
    AND a.id2 = b.id2 
    AND a.seq = b.ch 
    AND a.val = b.val 


;WITH rem_duplicates AS (
    SELECT *, dup = ROW_NUMBER() OVER (PARTITION by id2, seq, category ORDER BY id1 DESC) 
    FROM #T1 
) DELETE FROM rem_duplicates WHERE dup > 1 


SELECT * FROM #T1 ORDER BY id2 DESC, category ASC, seq ASC 

DROP TABLE #T1 
+0

感謝您的意見,Valerica !.我想,額外列的定義是我無法繞過迭代的地方。 –