2017-07-27 48 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 !.我想,额外列的定义是我无法绕过迭代的地方。 –