Tsql 按顺序排列行并填补缺少行的空白
我遇到了一个表格中缺少行的问题,这让我很头疼 作为基础数据,我有下表:Tsql 按顺序排列行并填补缺少行的空白,tsql,sequence,gaps-in-data,Tsql,Sequence,Gaps In Data,我遇到了一个表格中缺少行的问题,这让我很头疼 作为基础数据,我有下表: 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
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'
如果序列或模式被中断,它应该用null填充缺少的行,这样我就可以得到这个结果表:
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
等等
我要寻找的是一种不需要迭代就可以做到这一点的方法
我希望有人能帮忙
提前谢谢 我对您的输出有点困惑,请尝试以下方法: 更新
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
如果您能够在表中添加一个额外的列,该列定义了哪些[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
解决方案可能是:
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,它输出应该在最终输出中的所有ABCD行,并在rownum中对它们进行编号
最后,我在id2和rownum上用空格离开了join foobar。这样我们就得到了正确的行数,并且输出了原始数据中有值的位置。谢谢,非常感谢!但是1351和1411是在相同的序列中。所以1411应该紧跟在1351之后的第6行,而不是第10行谢谢你的输入,Valerica!。我想,额外列的定义是我无法绕过迭代的地方。非常感谢您的解决方案和解释!你真是个天才!