将 Table A 中的列匹配到 Table B 中的行值以更新 Table B 中的另一列

Match Columns in Table A to Row Values in Table B to update another Column in Table B

我想将 TableA 的列与 TableB 的一列中的值匹配,以便更新 TableB 中另一列中的值。

表A:

001100 001200 003000 004000 005000
1 0 1 1 0

表B:

Column_1 Score
001100
001200
003000
004000
005000

因此,例如,我希望将 TableB 中的“得分”列更新为 001100 的值“1”。因此结果 table 应如下所示:

Column_1 Score
001100 1
001200 0
003000 1
004000 1
005000 0

我知道如何通过硬编码和一次一行更新它:

Update [TableB]
Set Score = [001100]
From  [Table A]
Where [Column_1] = '001100'

但是我有超过 50 个这样的专栏,所以如果有人可以建议我如何在不必对列名称进行硬编码的情况下完成这项工作,那就太好了。因此,一个代码将从 TableA 中动态获取列的名称,然后将其与 tableB Column_1 值匹配。

如果您在 TableA 中的列名称是固定的并且不会更改,您可以构建一个临时 table 并针对临时 table 进行更新:

DECLARE @Scores TABLE (Column_1 varchar(20), Score int)

-- Build the data in the temporary table
INSERT @Scores (Column_1, Score)
SELECT '001100', [001100] FROM TableA
UNION ALL SELECT '001200', [001200] FROM TableA
UNION ALL SELECT '003000', [003000] FROM TableA
-- Repeat for all columns

UPDATE TableB
SET    Score = s.Score
FROM   TableB JOIN @Scores s ON TableB.[Column_1] = s.[Column_1]

如果TableA中有多行,您将需要管理临时数据中的数据。换句话说,如果您的临时 table 包含 TableB 中同一行的多行,那么更新将不会像您预期的那样工作。您需要对分数进行分组和求和:

-- Build the data in the temporary table
INSERT @Scores (Column_1, Score)
SELECT '001100', SUM([001100]) FROM TableA
UNION ALL SELECT '001200', SUM([001200]) FROM TableA
UNION ALL SELECT '003000', SUM([003000]) FROM TableA
-- Repeat for all columns

这是一个例子:

-- Source data
DECLARE @TableA TABLE([001100] int, [001200] int, [003000] int, [004000] int, [005000] int);
DECLARE @TableB TABLE([Column_1] varchar(20), Score int);

INSERT @TableA ([001100], [001200], [003000], [004000], [005000])
VALUES  (1, 0, 1, 1, 0);

INSERT @TableB ([Column_1])
VALUES ('001100'), ('001200'), ('003000'), ('004000'), ('005000');

-- Answer
DECLARE @Scores TABLE (Column_1 varchar(20), Score int);

INSERT @Scores (Column_1, Score)
SELECT '001100', SUM([001100]) FROM @TableA
UNION ALL SELECT '001200', SUM([001200]) FROM @TableA
UNION ALL SELECT '003000', SUM([003000]) FROM @TableA
UNION ALL SELECT '004000', SUM([004000]) FROM @TableA
UNION ALL SELECT '005000', SUM([005000]) FROM @TableA
;

UPDATE TableB
SET    Score = s.Score
FROM   @TableB TableB JOIN @Scores s ON TableB.[Column_1] = s.[Column_1];

SELECT * FROM @TableB;

结果如下:

Column_1 Score
001100 1
001200 0
003000 1
004000 1
005000 0

给你。

这将动态生成正确的 SQL 以从 Table A 中的值更新 Table B 中的 Score 任意数字 列。

唯一的要求是 Table A 中的列名称与 table B

中的 Column_1 的值匹配

首先我需要列的列表,这可以从 sys.columns 获得。 然后我使用 for xml path.

将它们连接成一个字符串

然后我能够动态构建一个更新语句,该语句使用列列表并将它们逆透视以匹配 TableB

中的行

最后执行动态构建的SQL.

如果您在(实际)表上有合适的索引,这将是高性能的。

create table TableA ([001100] int, [001200] int, [003000] int, [004000] int [005000] int)

insert into TableA
select 1,0,1,1,0

create table TableB (Column_1 varchar(10), Score int)

insert into TableB (Column_1) select '001100'   
insert into TableB (Column_1) select '001200'   
insert into TableB (Column_1) select '003000'   
insert into TableB (Column_1) select '004000'   
insert into TableB (Column_1) select '005000'



declare @cols nvarchar(max), @sql nvarchar(max)

select @cols=Stuff((
        select ', '+QuoteName(c.name )
        from sys.tables t join sys.columns c on c.object_id=t.object_id
        where t.[name]='TableA'
        for xml path(''), type
    ).value('.[1]', 'varchar(100)'), 1, 2, ''
)

set @sql='
update b set
    b.score=p.val
from (
    select ' + @cols + '
    from TableA -- where clause if relevant
) s
unpivot (
 val for col in (' + @cols + ')
) p
join TableB b on b.Column_1=p.col'

exec(@sql)