簡體   English   中英

使用漸進式row_number在分區函數上填充NULL值

[英]Fill NULL value with progressive row_number over partition function

我有的

從以下MyTable我只有NameNumber列。

我的目標是使用漸進數字填充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值,然后計算行數。 我怎樣才能填空值?

為什么我認為這不是一個重復的問題

我已經閱讀了這個問題這個問題,但我不認為它是重復的,因為他們不考慮PARTITION BY構造。


這是用於創建和填充表的腳本

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子句的row_number()函數根據Desidered_col分配新排名( select 1 or select null

select *, 
        row_number() over (partition by Name order by (select 1)) New_Desidered_col 
from #MyTable

為此,您需要一個指定表中行的順序的列。 您可以使用identity()函數執行此操作:

SELECT identity(int, 1, 1) as MyTableId, a.* 
INTO #MyTable
. . .

我非常確定SQL Server將遵循values()語句的順序,並且在實踐中將遵循union all的順序。 如果您願意,可以將此列明確地放在每一行中。

然后你可以用它來分配你的價值:

select t.*,
       row_number() over (partition by name order by mytableid) as desired_col
from #MyTable

此查詢有點復雜,但似乎返回您的預期結果。 唯一可能是錯誤的情況是有人沒有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值進行ordering_nulls並與CTE gaps_between_numbers連接,以了解每行應出現在哪個位置。

ordering_not_null_numbers對非NULL的值進行ordering_not_null_numbers 連續數字將具有相同的行號

最后一步是聯合CTE的ordering_not_null_numbersordering_nulls並進行所需的排序

Rextester DEMO

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM