列中两个值之间的重复值
Repeat value between two values in a column
我正在尝试重复列中的第一个特定非空值,直到同一列中的下一个特定非空值。我该怎么做?
数据如下所示:
ID | Msg
---+-----
1 |
2 |
3 |
4 |
5 | Beg
6 | End
7 |
8 | Beg
9 |
10 |
11 |
12 | End
应该是这样的:
ID | Msg
---+-----
1 |
2 |
3 |
4 |
5 | Beg
6 | End
7 |
8 | Beg
9 | Beg
10 | Beg
11 | Beg
12 | End
我调查了 LAG()
和 LEAD()
,但我一直认为我必须使用 CURSOR
。我只知道这些,但还没有在这种情况下使用它们。
由于您使用的是 MSSQL,因此您可以编写一个 CTE 来获得您要查找的结果。
试试这个 CTE:
declare @tab table
(
id int,
msg char(3)
)
insert into @tab
values
(1, ''),
(2, ''),
(3, ''),
(4, ''),
(5, 'Beg'),
(6, 'End'),
(7, ''),
(8, 'Beg'),
(9, ''),
(10, ''),
(11, ''),
(12, 'End')
;with cte as
(
select top 1 tab.id, tab.msg
from @tab tab
order by tab.id
union all
select tab.id, case when tab.msg = '' and cte.msg = 'beg' then cte.msg else tab.msg end
from @tab tab
inner join cte cte on cte.id + 1 = tab.id
)
select *
from cte
数据
DECLARE @id AS TABLE (
ID INT
, MSG VARCHAR(3)
)
INSERT INTO @ID (ID, MSG)
SELECT 1, ''
UNION
SELECT 2, ''
UNION
SELECT 3, ''
UNION
SELECT 4, ''
UNION
SELECT 5, 'Beg'
UNION
SELECT 6, 'End'
UNION
SELECT 7, ''
UNION
SELECT 8, 'Beg'
UNION
SELECT 9, ''
UNION
SELECT 10, ''
UNION
SELECT 11, ''
UNION
SELECT 12, 'End'
查询
SELECT
final.id
, CASE
WHEN msg = '' AND C.begCount>c.EndCount THEN 'Beg'
ELSE final.MSG
END Msg
FROM @id final
INNER JOIN
(
SELECT ID
, (SELECT COUNT(*) FROM @ID B WHERE B.ID < MAIN.ID AND MSG ='BEG') begCount
, (SELECT COUNT(*) FROM @ID B WHERE B.ID < MAIN.ID AND MSG ='END') EndCount
FROM @id MAIN
) C
ON C.ID = final.ID
您可以尝试以下代码,它适用于您提出的情况,但不确定它是否适用于所有其他情况,因为 case 语句特定于上述定位:
WITH cte AS(
SELECT *, LEAD(Msg, 1, 0) OVER (ORDER BY ID) AS leadval, LAG(Msg, 1, 0) OVER (ORDER BY ID) AS lagval
FROM msg),
cte2 AS(
SELECT cte.ID,
cte.Msg,
cte.leadval,
cte.lagval,
CASE WHEN cte.Msg = 'Beg' THEN 'Beg'
WHEN cte.Msg = '' AND cte.leadval = '' AND cte.lagval = 'Beg' THEN 'Beg'
WHEN cte.Msg = '' AND cte.leadval = 'END' THEN 'Beg'
ELSE cte.Msg end AS Msg2
FROM cte), cte3 AS(
SELECT *, LEAD(cte2.Msg2, 1, 0) OVER (ORDER BY cte2.ID) AS 'LeadVal2'
FROM cte2)
SELECT ID, CASE WHEN cte3.Msg2 = '' AND cte3.LeadVal2 = 'Beg' AND cte3.leadval <> 'Beg' THEN 'Beg' ELSE cte3.Msg2 END AS msg
FROM cte3
输出:
只是另一个使用标志和 sum() over
的选项
例子
Select ID
,Msg = case when sum( case when [Msg]='Beg' then 1 when [Msg]='End' then -1 else 0 end ) over (order by ID) = 1 and Msg='' then 'Beg' else Msg end
From YourTable
Returns
ID Msg
1
2
3
4
5 Beg
6 End
7
8 Beg
9 Beg
10 Beg
11 Beg
12 End
这里 sql 没有自连接 - 仅使用 window 函数
select
dat.id,
isnull(nullif(max(dat.msg) over (partition by dat.gr), 'End'), dat.msg) as msg
from (
select
dat.id,
dat.msg,
dat.wind + sum(dat.is_end) over (order by dat.id) as gr
from (
select
t.id,
t.msg,
sum(iif(t.msg = 'Beg' ,1,0)) over (order by t.id) as wind,
iif (t.msg = 'End', 1, 0) as is_end
from t
) dat
) dat
我正在尝试重复列中的第一个特定非空值,直到同一列中的下一个特定非空值。我该怎么做?
数据如下所示:
ID | Msg
---+-----
1 |
2 |
3 |
4 |
5 | Beg
6 | End
7 |
8 | Beg
9 |
10 |
11 |
12 | End
应该是这样的:
ID | Msg
---+-----
1 |
2 |
3 |
4 |
5 | Beg
6 | End
7 |
8 | Beg
9 | Beg
10 | Beg
11 | Beg
12 | End
我调查了 LAG()
和 LEAD()
,但我一直认为我必须使用 CURSOR
。我只知道这些,但还没有在这种情况下使用它们。
由于您使用的是 MSSQL,因此您可以编写一个 CTE 来获得您要查找的结果。
试试这个 CTE:
declare @tab table
(
id int,
msg char(3)
)
insert into @tab
values
(1, ''),
(2, ''),
(3, ''),
(4, ''),
(5, 'Beg'),
(6, 'End'),
(7, ''),
(8, 'Beg'),
(9, ''),
(10, ''),
(11, ''),
(12, 'End')
;with cte as
(
select top 1 tab.id, tab.msg
from @tab tab
order by tab.id
union all
select tab.id, case when tab.msg = '' and cte.msg = 'beg' then cte.msg else tab.msg end
from @tab tab
inner join cte cte on cte.id + 1 = tab.id
)
select *
from cte
数据
DECLARE @id AS TABLE (
ID INT
, MSG VARCHAR(3)
)
INSERT INTO @ID (ID, MSG)
SELECT 1, ''
UNION
SELECT 2, ''
UNION
SELECT 3, ''
UNION
SELECT 4, ''
UNION
SELECT 5, 'Beg'
UNION
SELECT 6, 'End'
UNION
SELECT 7, ''
UNION
SELECT 8, 'Beg'
UNION
SELECT 9, ''
UNION
SELECT 10, ''
UNION
SELECT 11, ''
UNION
SELECT 12, 'End'
查询
SELECT
final.id
, CASE
WHEN msg = '' AND C.begCount>c.EndCount THEN 'Beg'
ELSE final.MSG
END Msg
FROM @id final
INNER JOIN
(
SELECT ID
, (SELECT COUNT(*) FROM @ID B WHERE B.ID < MAIN.ID AND MSG ='BEG') begCount
, (SELECT COUNT(*) FROM @ID B WHERE B.ID < MAIN.ID AND MSG ='END') EndCount
FROM @id MAIN
) C
ON C.ID = final.ID
您可以尝试以下代码,它适用于您提出的情况,但不确定它是否适用于所有其他情况,因为 case 语句特定于上述定位:
WITH cte AS(
SELECT *, LEAD(Msg, 1, 0) OVER (ORDER BY ID) AS leadval, LAG(Msg, 1, 0) OVER (ORDER BY ID) AS lagval
FROM msg),
cte2 AS(
SELECT cte.ID,
cte.Msg,
cte.leadval,
cte.lagval,
CASE WHEN cte.Msg = 'Beg' THEN 'Beg'
WHEN cte.Msg = '' AND cte.leadval = '' AND cte.lagval = 'Beg' THEN 'Beg'
WHEN cte.Msg = '' AND cte.leadval = 'END' THEN 'Beg'
ELSE cte.Msg end AS Msg2
FROM cte), cte3 AS(
SELECT *, LEAD(cte2.Msg2, 1, 0) OVER (ORDER BY cte2.ID) AS 'LeadVal2'
FROM cte2)
SELECT ID, CASE WHEN cte3.Msg2 = '' AND cte3.LeadVal2 = 'Beg' AND cte3.leadval <> 'Beg' THEN 'Beg' ELSE cte3.Msg2 END AS msg
FROM cte3
输出:
只是另一个使用标志和 sum() over
例子
Select ID
,Msg = case when sum( case when [Msg]='Beg' then 1 when [Msg]='End' then -1 else 0 end ) over (order by ID) = 1 and Msg='' then 'Beg' else Msg end
From YourTable
Returns
ID Msg
1
2
3
4
5 Beg
6 End
7
8 Beg
9 Beg
10 Beg
11 Beg
12 End
这里 sql 没有自连接 - 仅使用 window 函数
select
dat.id,
isnull(nullif(max(dat.msg) over (partition by dat.gr), 'End'), dat.msg) as msg
from (
select
dat.id,
dat.msg,
dat.wind + sum(dat.is_end) over (order by dat.id) as gr
from (
select
t.id,
t.msg,
sum(iif(t.msg = 'Beg' ,1,0)) over (order by t.id) as wind,
iif (t.msg = 'End', 1, 0) as is_end
from t
) dat
) dat