T-SQL:我可以使用另一个表中的行更新表吗?

时间:2015-03-06 21:02:20

标签: sql sql-server tsql

我有一张看起来像这样的表

[UniqueID]-[1]-[2]-[3]-[etc... to 250
------------------------------
00000A    | 0 | 0 | 1 |
00000B    | 0 | 1 | 0 |
00000C    | 0 | 1 | 1 |

我从另一个表中转移了该表,其中包含两列,唯一ID和数字(1,2,3等)

我有另一个表有两列,一个数字和一个消除。例如,如果数字为2且消除为3,我将获取唯一ID 00000C,转到第3列,并将1更改为0。

过去,我手动写过:

UPDATE [TABLE] SET [3] = 0 WHERE [2] = 1

我需要这样做大约150次,所以编写一个查询来从第二个表中读取以修改第一个表格会更简洁。此外,当我必须进行更改时,我只需要修改表而不是更改查询本身。

我知道我可以通过旋转第二个表并使用动态SQL来实现这一点,如果必须的话,我会这样做,但我想知道你们是否有其他想法来解决这个问题。

基本上,我要做的是:

UPDATE [TABLE] SET [(SELECT elim FROM ElimTbl)] = 0 
WHERE [(SELECT num FROM ElimTbl)] = 1

我知道这是无效的,但我希望有人有更好的主意。

感谢您的时间!

3 个答案:

答案 0 :(得分:1)

目标表未规范化,因为[1], [2], ..., [150]只不过是一组重复的列(12)。这意味着目标表会破坏第一个正常形式。此问题会产生另一个问题:UPDATE语句应包含相同的表达式,其中包含少量修改(发现消除的[sub]查询)150次。

相反,我会使用规范化的目标表,当需要时,可以使用PIVOT运算符轻松地转移目标表中的数据:

/*
[UniqueID]-[1]-[2]-[3]-etc... 150
------------------------------
00000A    | 0 | 0 | 1 |
00000B    | 0 | 1 | 0 |
00000C    | 0 | 1 | 1 |
*/

DECLARE @Target TABLE (
    UniqueID    VARCHAR(6) NOT NULL,
    Num         INT NOT NULL,   
        PRIMARY KEY (UniqueID, Num),
    Value       BIT NOT NULL
);
INSERT  @Target 
VALUES  
('00000A', 3, 1),
('00000B', 2, 1),
('00000C', 2, 1), ('00000C', 3, 1);

DECLARE @Source TABLE (
    UniqueID    VARCHAR(6) NOT NULL,
        PRIMARY KEY (UniqueID),
    Num         INT NOT NULL
);
INSERT  @Source 
VALUES  
('00000B', 3), 
('00000C', 2);

SELECT * FROM @Target
SELECT * FROM @Source

- 中级查询

SELECT  s.*, x.*
FROM    @Source s
OUTER APPLY (
    SELECT  TOP(1) *
    FROM    @Target t
    WHERE   t.Num = s.Num
    AND     t.Value = 1
    AND     t.UniqueID >= s.UniqueID
    ORDER BY t.UniqueID 
) x
/*
Results
UniqueID Num UniqueID Num Value
-------- --- -------- --- -----
00000B   3   00000C   3   1
00000C   2   00000C   2   1
*/

- 最终查询

UPDATE  t           --| or DELETE t 
SET     Value = 0   --| 
FROM    @Target AS t
WHERE   EXISTS (
    SELECT  *
    FROM    @Source s
    CROSS APPLY (
        SELECT  TOP(1) *
        FROM    @Target t
        WHERE   t.Num = s.Num
        AND     t.Value = 1
        AND     t.UniqueID >= s.UniqueID
        ORDER BY t.UniqueID 
    ) x
    WHERE x.UniqueID = t.UniqueID
)

SELECT * FROM @Target
/*
Results:
UniqueID Num         Value
-------- ----------- -----
00000A   3           1
00000B   2           1
00000C   2           0
00000C   3           0
*/

- Pivot

;WITH CteSource 
AS 
(SELECT UniqueID, Num, CONVERT(TINYINT, Value) AS ValueAsInt FROM @Target)
SELECT  pvt.*
FROM    CteSource s
PIVOT( MAX(s.ValueAsInt) FOR s.Num IN ([1], [2], [3], /*...*/ [150]) ) pvt
/*
UniqueID 1    2    3    150
-------- ---- ---- ---- ----
00000A   NULL NULL 1    NULL --> NULLs can be replaced with 0 with ISNULL / COALESCE
00000B   NULL 1    NULL NULL
00000C   NULL 0    0    NULL
*/

答案 1 :(得分:0)

Update t1
Set t1.value = t2.value
FROM
t1
INNER JOIN t2 ON t1.KEY = t2.KEY

答案 2 :(得分:0)

花了一些时间后,我发现答案更好,更简单。

我的原始表格如下:

[Table A]
ID | Num
--------
A  | 3
B  | 2
C  | 2
C  | 3

我的另一张桌子是:

Num | Eliminate
---------------
2   | 3

基本上这意味着如果任何给定的ID同时分配了数字2和3,则应该删除3,同时离开2.如果我加入这些表,我得到这个:

ID | Num | Eliminate
--------------------
A  | 3   | NULL
B  | 2   | 3
C  | 2   | 3
C  | 3   | NULL

然后我可以生成一个带ID和Eliminate(没有空值)的表:

[Table B]
ID | Eliminate
---------------
B  | 3
C  | 3

最后,我可以使用以下内容生成输出:

SELECT [ID], [Num] FROM [Table A]
EXCEPT
SELECT [ID], [Eliminate] FROM [Table B]

这会产生输出:

ID | Num
--------
A  | 3
B  | 2
C  | 2

我正在寻找的是什么,现在如果我想要或执行任何其他操作,我可以转动它。这个解决方案比我想象的要简单得多,但是直到一位同事提出这个解决方案我才真正看到它......希望这可以帮助别人陷入同样的​​境地!