T-SQL:我可以使用另一个 table 中的行来更新 table 吗?
T-SQL: Can I update a table using rows from another table?
我有一个 table 看起来像这样
[UniqueID]-[1]-[2]-[3]-[etc... to 250
------------------------------
00000A | 0 | 0 | 1 |
00000B | 0 | 1 | 0 |
00000C | 0 | 1 | 1 |
我将 table 从另一个 table 转换为两列,唯一 ID 和数字(1、2、3 等)
我有另一个 table,它有两列,一个数字和一个消除。例如,如果数字是 2,消除是 3,我将取唯一 ID 00000C,转到第 3 列,并将 1 更改为 0。
以前手动写过:
UPDATE [TABLE] SET [3] = 0 WHERE [2] = 1
我需要这样做大约 150 次,因此编写查询以从第二个 table 读取以修改第一个会更加简洁。此外,当我必须进行更改时,我只需要修改 table 而不是对查询本身进行更改。
我知道我可以通过旋转第二个 table 并使用动态 SQL 来做到这一点,如果必须的话我会这样做,但我想知道你们是否有解决这个问题的一些其他想法。
基本上,我想要做的是:
UPDATE [TABLE] SET [(SELECT elim FROM ElimTbl)] = 0
WHERE [(SELECT num FROM ElimTbl)] = 1
我知道这是无效的,但我希望有人有更好的主意。
感谢您的宝贵时间!
Update t1
Set t1.value = t2.value
FROM
t1
INNER JOIN t2 ON t1.KEY = t2.KEY
目标 table 未标准化,因为 [1], [2], ..., [150]
只不过是一组重复的列 (1, 2)。这意味着 target table 打破了第一范式。这个问题会产生另一个问题:UPDATE
语句应该包含相同的表达式并进行少量修改(一个 [sub] 查询发现 elimination)第 150 次。
相反,我会使用规范化目标 table,并且在需要时,可以使用 PIVOT 运算符轻松旋转来自目标 table 的数据:
/*
[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
*/
-- 枢轴
;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
*/
花了一些时间后,我找到了一个效果更好、更简单的答案。
我原来的table是这样的:
[Table A]
ID | Num
--------
A | 3
B | 2
C | 2
C | 3
我的另一个table是:
Num | Eliminate
---------------
2 | 3
基本上这意味着如果任何给定的 ID 都被分配了数字 2 和 3,则 3 应该被删除而留下 2。如果我加入这些 tables,我得到这个:
ID | Num | Eliminate
--------------------
A | 3 | NULL
B | 2 | 3
C | 2 | 3
C | 3 | NULL
然后我可以生成一个带有 ID 的 table 并消除(没有空值):
[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
这就是我要找的东西,如果我愿意或执行任何其他操作,现在我可以旋转它。这个解决方案比我想象的要简单得多,但直到一位同事建议我才看到它......希望这可以帮助其他陷入同样情况的人!
我有一个 table 看起来像这样
[UniqueID]-[1]-[2]-[3]-[etc... to 250
------------------------------
00000A | 0 | 0 | 1 |
00000B | 0 | 1 | 0 |
00000C | 0 | 1 | 1 |
我将 table 从另一个 table 转换为两列,唯一 ID 和数字(1、2、3 等)
我有另一个 table,它有两列,一个数字和一个消除。例如,如果数字是 2,消除是 3,我将取唯一 ID 00000C,转到第 3 列,并将 1 更改为 0。
以前手动写过:
UPDATE [TABLE] SET [3] = 0 WHERE [2] = 1
我需要这样做大约 150 次,因此编写查询以从第二个 table 读取以修改第一个会更加简洁。此外,当我必须进行更改时,我只需要修改 table 而不是对查询本身进行更改。
我知道我可以通过旋转第二个 table 并使用动态 SQL 来做到这一点,如果必须的话我会这样做,但我想知道你们是否有解决这个问题的一些其他想法。
基本上,我想要做的是:
UPDATE [TABLE] SET [(SELECT elim FROM ElimTbl)] = 0
WHERE [(SELECT num FROM ElimTbl)] = 1
我知道这是无效的,但我希望有人有更好的主意。
感谢您的宝贵时间!
Update t1
Set t1.value = t2.value
FROM
t1
INNER JOIN t2 ON t1.KEY = t2.KEY
目标 table 未标准化,因为 [1], [2], ..., [150]
只不过是一组重复的列 (1, 2)。这意味着 target table 打破了第一范式。这个问题会产生另一个问题:UPDATE
语句应该包含相同的表达式并进行少量修改(一个 [sub] 查询发现 elimination)第 150 次。
相反,我会使用规范化目标 table,并且在需要时,可以使用 PIVOT 运算符轻松旋转来自目标 table 的数据:
/*
[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
*/
-- 枢轴
;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
*/
花了一些时间后,我找到了一个效果更好、更简单的答案。
我原来的table是这样的:
[Table A]
ID | Num
--------
A | 3
B | 2
C | 2
C | 3
我的另一个table是:
Num | Eliminate
---------------
2 | 3
基本上这意味着如果任何给定的 ID 都被分配了数字 2 和 3,则 3 应该被删除而留下 2。如果我加入这些 tables,我得到这个:
ID | Num | Eliminate
--------------------
A | 3 | NULL
B | 2 | 3
C | 2 | 3
C | 3 | NULL
然后我可以生成一个带有 ID 的 table 并消除(没有空值):
[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
这就是我要找的东西,如果我愿意或执行任何其他操作,现在我可以旋转它。这个解决方案比我想象的要简单得多,但直到一位同事建议我才看到它......希望这可以帮助其他陷入同样情况的人!