在分区函数上用渐进 row_number 填充 NULL 值
Fill NULL value with progressive row_number over partition function
我有什么
从下面的#MyTable
我只有 Name
和 Number
列。
我的目标是用累进数字填充 valus where Number = NULL 并获取我写入 Desidered_col
列的值。
+------+--------+---------------+
| Name | Number | Desidered_col |
+------+--------+---------------+
| John | 1 | 1 |
| John | 2 | 2 |
| John | 3 | 3 |
| John | NULL | 4 |
| John | NULL | 5 |
| John | 6 | 6 |
| Mike | 1 | 1 |
| Mike | 2 | 2 |
| Mike | NULL | 3 |
| Mike | 4 | 4 |
| Mike | 5 | 5 |
| Mike | 6 | 6 |
+------+--------+---------------+
我试过的
我试过以下查询
SELECT Name, Number, row_number() OVER(PARTITION BY [Name] ORDER BY Number ASC) AS rn
FROM #MyTable
但是它把所有的 NULL 值放在第一位,然后计算行数。
如何填充空值?
为什么我认为不是重复问题
我读过 this question and this question 但我不认为它是重复的,因为他们没有考虑 PARTITION BY
结构。
这是创建和填充 table
的脚本
SELECT *
INTO #MyTable
FROM (
SELECT 'John' AS [Name], 1 AS [Number], 1 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 2 AS [Number], 2 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 3 AS [Number], 3 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number], 4 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number], 5 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 6 AS [Number], 6 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 1 AS [Number], 1 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 2 AS [Number], 2 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], NULL AS [Number], 3 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 4 AS [Number], 4 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 5 AS [Number], 5 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 6 AS [Number], 6 AS [Desidered_col]
) A
您还可以使用带有 ORDER BY
子句 (select 1 or select null
)
的 row_number()
函数,根据 Desidered_col 分配新排名
select *,
row_number() over (partition by Name order by (select 1)) New_Desidered_col
from #MyTable
为此,您需要一个列来指定 table 中行的顺序。您可以使用 identity()
函数执行此操作:
SELECT identity(int, 1, 1) as MyTableId, a.*
INTO #MyTable
. . .
我很确定 SQL 服务器将遵循 values()
语句的顺序并且实际上将遵循 union all
的顺序。如果愿意,您可以明确地将此列放在每一行中。
然后你可以使用它来分配你的值:
select t.*,
row_number() over (partition by name order by mytableid) as desired_col
from #MyTable
这个查询有点复杂,但似乎 return 您的预期结果。唯一可能错误的情况是某人没有 Number = 1
。
想法是您必须找到数字之间的空隙并计算可以使用多少空值来填充它们。
示例数据
create table #myTable (
[Name] varchar(20)
, [Number] int
)
insert into #myTable
insert into #myTable
SELECT 'John' AS [Name], 1 AS [Number] UNION ALL
SELECT 'John' AS [Name], 2 AS [Number]UNION ALL
SELECT 'John' AS [Name], 3 AS [Number] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number] UNION ALL
SELECT 'John' AS [Name], 6 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 1 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 2 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], NULL AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 4 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 5 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 6 AS [Number]
查询
;with gaps_between_numbers as (
select
t.Name, cnt = t.nextNum - t.Number - 1, dr = dense_rank() over (partition by t.Name order by t.Number)
, rn = row_number() over (partition by t.Name order by t.Number)
from (
select
Name, Number, nextNum = isnull(lead(Number) over (partition by Name order by number), Number + 1)
from
#myTable
where
Number is not null
) t
join master.dbo.spt_values v on t.nextNum - t.Number - 1 > v.number
where
t.nextNum - t.Number > 1
and v.type = 'P'
)
, ordering_nulls as (
select
t.Name, dr = isnull(q.dr, 2147483647)
from (
select
Name, rn = row_number() over (partition by Name order by (select 1))
from
#myTable
where
Number is null
) t
left join gaps_between_numbers q on t.Name = q.Name and t.rn = q.rn
)
, ordering_not_null_numbers as (
select
Name, Number, rn = dense_rank() over (partition by Name order by gr)
from (
select
Name, Number, gr = sum(lg) over (partition by Name order by Number)
from (
select
Name, Number, lg = iif(Number - lag(Number) over (partition by Name order by Number) = 1, 0, 1)
from
#myTable
where
Number is not null
) t
) t
)
select
Name, Number
, Desidered_col = row_number() over (partition by Name order by rn, isnull(Number, 2147483647))
from (
select * from ordering_not_null_numbers
union all
select Name, null, dr from ordering_nulls
) t
CTE gaps_between_numbers
正在寻找不连续的数字。 Number
当前行和下一行之间的差异显示可以使用多少 NULL 值来填补空白。然后 master.dbo.spt_values
用于将每一行乘以该数量。在 gaps_between_numbers
中,dr
列是间隙数,cnt
是需要使用的 NULL 值的数量。
ordering_nulls
仅对 NULL 值排序并与 CTE 连接 gaps_between_numbers
以了解每一行应出现在哪个位置。
ordering_not_null_numbers
排序非 NULL 的值。连续编号将具有相同的行号
最后一步是合并 CTE 的 ordering_not_null_numbers
和 ordering_nulls
并进行所需的排序
我有什么
从下面的#MyTable
我只有 Name
和 Number
列。
我的目标是用累进数字填充 valus where Number = NULL 并获取我写入 Desidered_col
列的值。
+------+--------+---------------+
| Name | Number | Desidered_col |
+------+--------+---------------+
| John | 1 | 1 |
| John | 2 | 2 |
| John | 3 | 3 |
| John | NULL | 4 |
| John | NULL | 5 |
| John | 6 | 6 |
| Mike | 1 | 1 |
| Mike | 2 | 2 |
| Mike | NULL | 3 |
| Mike | 4 | 4 |
| Mike | 5 | 5 |
| Mike | 6 | 6 |
+------+--------+---------------+
我试过的
我试过以下查询
SELECT Name, Number, row_number() OVER(PARTITION BY [Name] ORDER BY Number ASC) AS rn
FROM #MyTable
但是它把所有的 NULL 值放在第一位,然后计算行数。 如何填充空值?
为什么我认为不是重复问题
我读过 this question and this question 但我不认为它是重复的,因为他们没有考虑 PARTITION BY
结构。
这是创建和填充 table
的脚本SELECT *
INTO #MyTable
FROM (
SELECT 'John' AS [Name], 1 AS [Number], 1 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 2 AS [Number], 2 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 3 AS [Number], 3 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number], 4 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number], 5 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 6 AS [Number], 6 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 1 AS [Number], 1 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 2 AS [Number], 2 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], NULL AS [Number], 3 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 4 AS [Number], 4 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 5 AS [Number], 5 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 6 AS [Number], 6 AS [Desidered_col]
) A
您还可以使用带有 ORDER BY
子句 (select 1 or select null
)
row_number()
函数,根据 Desidered_col 分配新排名
select *,
row_number() over (partition by Name order by (select 1)) New_Desidered_col
from #MyTable
为此,您需要一个列来指定 table 中行的顺序。您可以使用 identity()
函数执行此操作:
SELECT identity(int, 1, 1) as MyTableId, a.*
INTO #MyTable
. . .
我很确定 SQL 服务器将遵循 values()
语句的顺序并且实际上将遵循 union all
的顺序。如果愿意,您可以明确地将此列放在每一行中。
然后你可以使用它来分配你的值:
select t.*,
row_number() over (partition by name order by mytableid) as desired_col
from #MyTable
这个查询有点复杂,但似乎 return 您的预期结果。唯一可能错误的情况是某人没有 Number = 1
。
想法是您必须找到数字之间的空隙并计算可以使用多少空值来填充它们。
示例数据
create table #myTable (
[Name] varchar(20)
, [Number] int
)
insert into #myTable
insert into #myTable
SELECT 'John' AS [Name], 1 AS [Number] UNION ALL
SELECT 'John' AS [Name], 2 AS [Number]UNION ALL
SELECT 'John' AS [Name], 3 AS [Number] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number] UNION ALL
SELECT 'John' AS [Name], 6 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 1 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 2 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], NULL AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 4 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 5 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 6 AS [Number]
查询
;with gaps_between_numbers as (
select
t.Name, cnt = t.nextNum - t.Number - 1, dr = dense_rank() over (partition by t.Name order by t.Number)
, rn = row_number() over (partition by t.Name order by t.Number)
from (
select
Name, Number, nextNum = isnull(lead(Number) over (partition by Name order by number), Number + 1)
from
#myTable
where
Number is not null
) t
join master.dbo.spt_values v on t.nextNum - t.Number - 1 > v.number
where
t.nextNum - t.Number > 1
and v.type = 'P'
)
, ordering_nulls as (
select
t.Name, dr = isnull(q.dr, 2147483647)
from (
select
Name, rn = row_number() over (partition by Name order by (select 1))
from
#myTable
where
Number is null
) t
left join gaps_between_numbers q on t.Name = q.Name and t.rn = q.rn
)
, ordering_not_null_numbers as (
select
Name, Number, rn = dense_rank() over (partition by Name order by gr)
from (
select
Name, Number, gr = sum(lg) over (partition by Name order by Number)
from (
select
Name, Number, lg = iif(Number - lag(Number) over (partition by Name order by Number) = 1, 0, 1)
from
#myTable
where
Number is not null
) t
) t
)
select
Name, Number
, Desidered_col = row_number() over (partition by Name order by rn, isnull(Number, 2147483647))
from (
select * from ordering_not_null_numbers
union all
select Name, null, dr from ordering_nulls
) t
CTE gaps_between_numbers
正在寻找不连续的数字。 Number
当前行和下一行之间的差异显示可以使用多少 NULL 值来填补空白。然后 master.dbo.spt_values
用于将每一行乘以该数量。在 gaps_between_numbers
中,dr
列是间隙数,cnt
是需要使用的 NULL 值的数量。
ordering_nulls
仅对 NULL 值排序并与 CTE 连接 gaps_between_numbers
以了解每一行应出现在哪个位置。
ordering_not_null_numbers
排序非 NULL 的值。连续编号将具有相同的行号
最后一步是合并 CTE 的 ordering_not_null_numbers
和 ordering_nulls
并进行所需的排序