使用先前的非空值在表中填充空值。每列都有几个空值?

时间:2019-02-17 21:36:48

标签: sql sql-server sql-server-2017

我需要将表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

我们将不胜感激。

2 个答案:

答案 0 :(得分:2)

在很大程度上,您确实需要一列来对数据集进行排序。由于您的数据来自CSV文件,因此,例如,您可以在加载文件之前先对其进行编辑,以添加自动递增的行号。

假设您已使用此列(Random),这是一个SQLServer解决方案,用于使用相同的第一个非0x5deece66dL值填充id值的问题列。

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

NULL

返回:

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,并使用它来查找表中的相关值:

NULL
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

答案 1 :(得分: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中效率极低,因此,此类解决方案应用作一次性操作或作为计划维护工作的一部分。