【问题标题】:Match Columns in Table A to Row Values in Table B to update another Column in Table B将表 A 中的列与表 B 中的行值匹配以更新表 B 中的另一列
【发布时间】:2021-06-06 17:52:30
【问题描述】:

我想将 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”。因此结果表应如下所示:

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] 中是否只有 1 行? [TableA] 中的列名是否固定(已知且不会更改)?为什么[TableB] 中的001100 的得分是0 而不是1(因为它在TableA 中是1)?
  • 你看过JOINS吗?
  • 嗨,Ryan,在 [TableA] 中会有更多的一行。但一次,我将只过滤/选择一行。因此,我在上面的示例中只保留了一行。是的,[TableA] 中的列名保持不变。关于最后一部分,这是一个错字。我现在修好了,谢谢:)
  • 嗨布拉德,我无法使用连接,因为共同点是行和列之间,而不是列到列之间。

标签: sql sql-server tsql sql-server-2008


【解决方案1】:

给你。

这将动态生成正确的 SQL,以根据Table A 中的值更新Table B 中的Score 以用于任意数量列。

唯一的要求是Table A 中的列名与table BColumn_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)

【讨论】:

  • 不错。您还可以自动化insert into TableB (Column_1) select '001100' 代码,因为如果TableB 中不存在该行,则不会更新该行。此外,如果处理代码重复运行,则可能需要在下次运行之前清除 TableB
  • 插入 tableB 只是测试的设置代码,它不是解决方案的一部分。插入这些行取决于 OP,我认为这不是问题!
【解决方案2】:

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

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 中存在多于一行,则需要管理临时数据中的数据。换句话说,如果您的临时表在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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    相关资源
    最近更新 更多