使用先前的非空值填充表中的空值。每列的空值很少?

问题描述 投票:2回答:2

我需要将表A转换为表B(即使用先前的每个列的非空值填充所有空值)

主要任务是使用每列的先前非空值填充空值。

这是原始表:

FromCompany Container   Numbers     ToCompany        Location
DISCOVERY   HALU 330308   5         MAGNA CHARGE     St-Laurent
            ATSU 827944   0         LEEZA DIST. 
                          4     
COLUMBIA    CAIU 807457   3         La Cie Canada    Baie D'Urfe
                          6     
                          0     

决赛桌应该是:

FromCompany Container   Numbers ToCompany       Location
DISCOVERY   HALU 330308 5       MAGNA CHARGE    St-Laurent
DISCOVERY   ATSU 827944 0       LEEZA DIST      St-Laurent
DISCOVERY   ATSU 827944 4       LEEZA DIST      St-Laurent
COLUMBIA    CAIU 807457 3       La Cie Canada   Baie D'Urfe
COLUMBIA    CAIU 807457 6       La Cie Canada   Baie D'Urfe
COLUMBIA    CAIU 807457 0       La Cie Canada   Baie D'Urfe

非常感谢帮助。

sql sql-server sql-server-2017
2个回答
2
投票

在很大程度上评论时,您需要一列来订购数据集。由于您的数据来自CSV文件,因此您可以在加载文件之前编辑该文件以添加自动增加的行号。

假设你有这个列(id),这里是一个SQLServer解决方案,用于填充NULL值的问题,在同一列中使用第一个前面的非NULL值。

基本思想是将每个记录放入一个组中,该组的编号对应于具有非空值的第一个记录的id。要填充5列,我们需要5组。

SELECT
    t.* ,
    MAX(CASE WHEN FromCompany IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpFromCompany,
    MAX(CASE WHEN Container   IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpContainer,
    MAX(CASE WHEN Numbers     IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpNumbers,
    MAX(CASE WHEN ToCompany   IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpToCompany,
    MAX(CASE WHEN Location    IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpLocation
FROM mytable t

退货:

id | FromCompany | Container   | Numbers | ToCompany     | Location    | grpFromCompany | grpContainer | grpNumbers | grpToCompany | grpLocation
-: | :---------- | :---------- | ------: | :------------ | :---------- | -------------: | -----------: | ---------: | -----------: | ----------:
 1 | DISCOVERY   | HALU 330308 |       5 | MAGNA CHARGE  | St-Laurent  |              1 |            1 |          1 |            1 |           1
 2 | null        | ATSU 827944 |       0 | LEEZA DIST.   | null        |              1 |            2 |          2 |            2 |           1
 3 | null        | null        |       4 | null          | null        |              1 |            2 |          3 |            2 |           1
 4 | COLUMBIA    | CAIU 807457 |       3 | La Cie Canada | Baie D'Urfe |              4 |            4 |          4 |            4 |           4
 5 | null        | null        |       6 | null          | null        |              4 |            4 |          5 |            4 |           4
 6 | null        | null        |       0 | null          | null        |              4 |            4 |          6 |            4 |           4

现在我们可以将其转换为CTE,并使用它来查找表中的相关值:

WITH mycte AS (
    SELECT
        t.* ,
        MAX(CASE WHEN FromCompany IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpFromCompany,
        MAX(CASE WHEN Container   IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpContainer,
        MAX(CASE WHEN Numbers     IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpNumbers,
        MAX(CASE WHEN ToCompany   IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpToCompany,
        MAX(CASE WHEN Location    IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grpLocation
    FROM mytable t
)
SELECT 
   id,
   (SELECT FromCompany FROM mytable WHERE id = grpFromCompany) AS FromCompany,
   (SELECT Container   FROM mytable WHERE id = grpFromCompany) AS Container,
   (SELECT Numbers     FROM mytable WHERE id = grpNumbers) AS Numbers,
   (SELECT ToCompany   FROM mytable WHERE id = grpToCompany) AS ToCompany,
   (SELECT Location    FROM mytable WHERE id = grpLocation) AS Location
FROM mycte 

GO
id | FromCompany | Container   | Numbers | ToCompany     | Location   
-: | :---------- | :---------- | ------: | :------------ | :----------
 1 | DISCOVERY   | HALU 330308 |       5 | MAGNA CHARGE  | St-Laurent 
 2 | DISCOVERY   | HALU 330308 |       0 | LEEZA DIST.   | St-Laurent 
 3 | DISCOVERY   | HALU 330308 |       4 | LEEZA DIST.   | St-Laurent 
 4 | COLUMBIA    | CAIU 807457 |       3 | La Cie Canada | Baie D'Urfe
 5 | COLUMBIA    | CAIU 807457 |       6 | La Cie Canada | Baie D'Urfe
 6 | COLUMBIA    | CAIU 807457 |       0 | La Cie Canada | Baie D'Urfe

db <>小提琴here


0
投票

通常,如果您的表具有标识列或保证行排序的方法,您可以使用CTE以相对效率实现此目的。但是,我们在这里没有那么奢侈,所以另一个解决方案是使用效率低得多的CURSOR

-- Cursor variables
DECLARE @FromCompanyCursor varchar(20),
        @ContainerCursor varchar(20),
        @NumbersCursor int,
        @ToCompanyCursor varchar(20),
        @LocationCursor varchar(20),
        @FromCompany varchar(20),
        @Container varchar(20),
        @Numbers int,
        @ToCompany varchar(20),
        @Location varchar(20);


-- Cursor declaration
DECLARE C CURSOR FOR
(
SELECT  FromCompany,
        Container,
        Numbers,
        ToCompany,
        Location
FROM TableName
)
FOR UPDATE OF FromCompany, Container, Numbers, ToCompany, Location;

OPEN C;

-- Get first row from the cursor
FETCH NEXT FROM C INTO @FromCompanyCursor, @ContainerCursor, @NumbersCursor, @ToCompanyCursor, @LocationCursor;

-- While we still have rows to iterate over
WHILE @@FETCH_STATUS = 0
BEGIN
    -- Keep track of the last non-null value
    SELECT @FromCompany = CASE WHEN @FromCompanyCursor IS NOT NULL THEN @FromCompanyCursor ELSE @FromCompany END,
           @Container = CASE WHEN @ContainerCursor IS NOT NULL THEN @ContainerCursor ELSE @Container END,
           @Numbers = CASE WHEN @NumbersCursor IS NOT NULL THEN @NumbersCursor ELSE @Numbers END,
           @ToCompany = CASE WHEN @ToCompanyCursor IS NOT NULL THEN @ToCompanyCursor ELSE @ToCompany END,
           @Location = CASE WHEN @LocationCursor IS NOT NULL THEN @LocationCursor ELSE @Location END;

    -- Update the table with the last non-null values
    UPDATE TableName
    SET FromCompany = @FromCompany,
        Container = @Container,
        Numbers = @Numbers,
        ToCompany = @ToCompany,
        Location = @Location
    WHERE CURRENT OF C;

    -- Get the next row from the cursor
    FETCH NEXT FROM C INTO @FromCompanyCursor, @ContainerCursor, @NumbersCursor, @ToCompanyCursor, @LocationCursor;
END

-- Don't forget to close the cursor!
CLOSE C;
DEALLOCATE C;

请注意,像SQL Server这样的基于过程的操作非常低效,因此像这样的解决方案应该用作一次性操作,或者作为计划维护作业的一部分。

© www.soinside.com 2019 - 2024. All rights reserved.