如何从SQL Server中的select执行update?

How do I UPDATE from a SELECT in SQL Server?

在SQL Server中,可以使用SELECT语句将insert转换为表:

1
2
3
4
INSERT INTO TABLE (col1, col2, col3)
SELECT col1, col2, col3
FROM other_table
WHERE SQL = 'cool'

是否也可以通过SELECT进行更新?我有一个包含这些值的临时表,希望使用这些值更新另一个表。也许是这样:

1
2
3
4
5
UPDATE TABLE SET col1, col2
SELECT col1, col2
FROM other_table
WHERE SQL = 'cool'
WHERE TABLE.id = other_table.id

1
2
3
4
5
6
7
8
9
10
11
UPDATE
    Table_A
SET
    Table_A.col1 = Table_B.col1,
    Table_A.col2 = Table_B.col2
FROM
    Some_Table AS Table_A
    INNER JOIN Other_Table AS Table_B
        ON Table_A.id = Table_B.id
WHERE
    Table_A.col3 = 'cool'


在SQL Server 2008(或更高版本)中,使用MERGE

1
2
3
4
5
6
7
8
MERGE INTO YourTable T
   USING other_table S
      ON T.id = S.id
         AND S.tsql = 'cool'
WHEN MATCHED THEN
   UPDATE
      SET col1 = S.col1,
          col2 = S.col2;

可选地:

1
2
3
4
5
6
7
8
9
10
11
MERGE INTO YourTable T
   USING (
          SELECT id, col1, col2
            FROM other_table
           WHERE tsql = 'cool'
         ) S
      ON T.id = S.id
WHEN MATCHED THEN
   UPDATE
      SET col1 = S.col1,
          col2 = S.col2;


1
2
3
4
5
6
7
8
UPDATE TABLE
SET Col1 = i.Col1,
    Col2 = i.Col2
FROM (
    SELECT ID, Col1, Col2
    FROM other_table) i
WHERE
    i.ID = TABLE.ID


我将修改罗宾对以下问题的完美回答:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
UPDATE TABLE
SET TABLE.col1 = other_table.col1,
 TABLE.col2 = other_table.col2
FROM
    TABLE
INNER JOIN other_table ON TABLE.id = other_table.id
WHERE
    TABLE.col1 != other_table.col1
OR TABLE.col2 != other_table.col2
OR (
    other_table.col1 IS NOT NULL
    AND TABLE.col1 IS NULL
)
OR (
    other_table.col2 IS NOT NULL
    AND TABLE.col2 IS NULL
)

如果没有WHERE子句,即使不需要受影响的行也会受到影响,这可能(可能)导致重新计算索引或激发真正不应该激发的触发器。


单程

1
2
3
4
5
6
7
8
9
UPDATE t
SET t.col1 = o.col1,
    t.col2 = o.col2
FROM
    other_table o
  JOIN
    t ON t.id = o.id
WHERE
    o.sql = 'cool'

另一个尚未提到的可能性是将SELECT语句本身放入CTE,然后更新CTE。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
;WITH CTE
     AS (SELECT T1.Col1,
                T2.Col1 AS _Col1,
                T1.Col2,
                T2.Col2 AS _Col2
         FROM   T1
                JOIN T2
                  ON T1.id = T2.id
         /*Where clause added to exclude rows that are the same in both tables
           Handles NULL values correctly*/

         WHERE EXISTS(SELECT T1.Col1,
                             T1.Col2
                       EXCEPT
                       SELECT T2.Col1,
                              T2.Col2))
UPDATE CTE
SET    Col1 = _Col1,
       Col2 = _Col2

这样做的好处是,可以很容易地单独运行SELECT语句,首先对结果进行健全性检查,但如果源表和目标表中的列名称相同,则需要像上面那样对这些列进行别名。

这与其他四个答案中显示的专有UPDATE ... FROM语法也有相同的限制。如果源表位于一对多联接的多侧,那么无法确定哪些可能匹配的联接记录将用于Update(如果试图多次更新同一行,MERGE会通过引发错误来避免此问题)。


对于记录(以及其他像我这样的搜索),您可以在MySQL中这样做:

1
2
3
UPDATE first_table, second_table
SET first_table.color = second_table.color
WHERE first_table.id = second_table.foreign_id


使用别名:

1
2
3
4
5
6
UPDATE t
   SET t.col1 = o.col1
  FROM table1 AS t
         INNER JOIN
       table2 AS o
         ON t.id = o.id

简单的方法是:

1
2
3
4
5
6
7
8
9
UPDATE
    table_to_update,
    table_info
SET
    table_to_update.col1 = table_info.col1,
    table_to_update.col2 = table_info.col2

WHERE
    table_to_update.ID = table_info.ID


这可能是执行更新(例如,主要用于某个过程)的特定原因,或者对其他人来说是显而易见的,但也应该说明,您可以在不使用join的情况下执行update select语句(如果您正在更新的表之间没有公共字段)。

1
2
3
4
5
6
7
8
9
UPDATE
    TABLE
SET
    TABLE.example = a.value
FROM
    TableExample a
WHERE
    TABLE.field = *KEY VALUE* -- finds the row in Table
    AND a.field = *KEY VALUE* -- finds the row in TableExample a

下面是另一个有用的语法:

1
2
3
4
5
6
7
UPDATE suppliers
SET supplier_name = (SELECT customers.name
                     FROM customers
                     WHERE customers.customer_id = suppliers.supplier_id)
WHERE EXISTS (SELECT customers.name
              FROM customers
              WHERE customers.customer_id = suppliers.supplier_id);

它使用"Where exist"检查是否为空。


我添加这个只是为了让你能看到一个快速的方法来写它,这样你就可以在进行更新之前检查将要更新的内容。

1
2
3
4
5
6
7
UPDATE TABLE
SET  TABLE.col1 = other_table.col1,
     TABLE.col2 = other_table.col2
--select Table.col1, other_table.col,Table.col2,other_table.col2, *  
FROM     TABLE
INNER JOIN     other_table
    ON     TABLE.id = other_table.id

如果使用MySQL而不是SQL Server,则语法为:

1
2
3
4
5
UPDATE Table1
INNER JOIN Table2
ON Table1.id = Table2.id
SET Table1.col1 = Table2.col1,
    Table1.col2 = Table2.col2

在SQL数据库中使用内部联接从select更新

因为这篇文章的回复太多了,而且投票最多,所以我想我也会在这里提出我的建议。尽管这个问题很有趣,但我在许多论坛网站上都看到过,并用截图进行了内部连接的解决方案。

首先,我创建了一个名为schooldold的表,并插入了一些与列名相关的记录,然后执行它。

然后我执行了select命令来查看插入的记录。

></P><P>然后我创建了一个名为schoolNew的新表,并对其执行上面的操作。</P><P><img src=


如果您想将表与其自身连接起来(这种情况不会太频繁):

1
2
3
4
5
UPDATE t1                    -- just reference table alias here
SET t1.somevalue = t2.somevalue
FROM table1 t1               -- these rows will be the targets
INNER JOIN table1 t2         -- these rows will be used as source
ON ..................        -- the join clause is whatever suits you


以下示例使用派生表(FROM子句后的select语句)返回旧值和新值以进行进一步更新:

1
2
3
4
5
6
7
8
9
10
UPDATE x
SET    x.col1 = x.newCol1,
       x.col2 = x.newCol2
FROM   (SELECT t.col1,
               t2.col1 AS newCol1,
               t.col2,
               t2.col2 AS newCol2
        FROM   [TABLE] t
               JOIN other_table t2
                 ON t.ID = t2.ID) x

通过CTE更新比这里的其他答案更易读:

1
2
3
4
5
6
7
8
9
10
;WITH cte
     AS (SELECT col1,col2,id
         FROM   other_table
         WHERE  SQL = 'cool')
UPDATE A
SET    A.col1 = B.col1,
       A.col2 = B.col2
FROM   TABLE A
       INNER JOIN cte B
               ON A.id = B.id

如果您使用的是SQL Server,那么您可以在不指定联接的情况下从另一个表更新一个表,并且只需从where子句链接这两个表即可。这使得SQL查询更加简单:

1
2
3
4
5
6
7
UPDATE Table1
SET Table1.col1 = Table2.col1,
    Table1.col2 = Table2.col2
FROM
    Table2
WHERE
    Table1.id = Table2.id

另一种方法是使用派生表:

1
2
3
4
5
6
UPDATE t
SET t.col1 = a.col1
    ,t.col2 = a.col2
FROM (
SELECT id, col1, col2 FROM @tbl2) a
INNER JOIN @tbl1 t ON t.id = a.id

样本数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DECLARE @tbl1 TABLE (id INT, col1 VARCHAR(10), col2 VARCHAR(10))
DECLARE @tbl2 TABLE (id INT, col1 VARCHAR(10), col2 VARCHAR(10))

INSERT @tbl1 SELECT 1, 'a', 'b' UNION SELECT 2, 'b', 'c'

INSERT @tbl2 SELECT 1, '1', '2' UNION SELECT 2, '3', '4'

UPDATE t
SET t.col1 = a.col1
    ,t.col2 = a.col2
FROM (
SELECT id, col1, col2 FROM @tbl2) a
INNER JOIN @tbl1 t ON t.id = a.id

SELECT * FROM @tbl1
SELECT * FROM @tbl2


1
2
3
4
5
UPDATE TQ
SET TQ.IsProcessed = 1, TQ.TextName = 'bla bla bla'
FROM TableQueue TQ
INNER JOIN TableComment TC ON TC.ID = TQ.TCID
WHERE TQ.IsProcessed = 0

要确保正在更新所需内容,请首先选择

1
2
3
4
SELECT TQ.IsProcessed, 1 AS NewValue1, TQ.TextName, 'bla bla bla' AS NewValue2
FROM TableQueue TQ
INNER JOIN TableComment TC ON TC.ID = TQ.TCID
WHERE TQ.IsProcessed = 0

用途:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DROP TABLE uno
DROP TABLE dos

CREATE TABLE uno
(
    uid INT,
    col1 CHAR(1),
    col2 CHAR(2)
)
CREATE TABLE dos
(
    did INT,
    col1 CHAR(1),
    col2 CHAR(2),
    [SQL] CHAR(4)
)
INSERT INTO uno(uid) VALUES (1)
INSERT INTO uno(uid) VALUES (2)
INSERT INTO dos VALUES (1,'a','b',NULL)
INSERT INTO dos VALUES (2,'c','d','cool')

SELECT * FROM uno
SELECT * FROM dos

要么:

1
2
UPDATE uno SET col1 = (SELECT col1 FROM dos WHERE uid = did AND [SQL]='cool'),
col2 = (SELECT col2 FROM dos WHERE uid = did AND [SQL]='cool')

或:

1
2
3
4
5
UPDATE uno SET col1=d.col1,col2=d.col2 FROM uno
INNER JOIN dos d ON uid=did WHERE [SQL]='cool'

SELECT * FROM uno
SELECT * FROM dos

如果两个表中的ID列名相同,则只需将表名放在要更新的表之前,并为所选表使用别名,即:

1
2
UPDATE uno SET col1 = (SELECT col1 FROM dos d WHERE uno.[id] = d.[id] AND [SQL]='cool'),
col2  = (SELECT col2 FROM dos d WHERE uno.[id] = d.[id] AND [SQL]='cool')

甚至还有一种更短的方法,可能会让您感到惊讶:

示例数据集:

1
2
3
4
5
CREATE TABLE #SOURCE ([ID] INT, [DESC] VARCHAR(10));
CREATE TABLE #DEST   ([ID] INT, [DESC] VARCHAR(10));

INSERT INTO #SOURCE VALUES(1,'Desc_1'), (2, 'Desc_2'), (3, 'Desc_3');
INSERT INTO #DEST   VALUES(1,'Desc_4'), (2, 'Desc_5'), (3, 'Desc_6');

代码:

1
2
3
4
UPDATE #DEST
SET #DEST.[DESC] = #SOURCE.[DESC]
FROM #SOURCE
WHERE #DEST.[ID] = #SOURCE.[ID];


在接受的回答中,在以下时间之后:

1
2
3
SET
Table_A.col1 = Table_B.col1,
Table_A.col2 = Table_B.col2

我补充说:

1
OUTPUT deleted.*, inserted.*

我通常做的是将所有内容放入一个滚动备份的事务中,并使用"OUTPUT":这样,我就能看到即将发生的一切。当我对我所看到的感到满意时,我把ROLLBACK改为COMMIT

我通常需要记录我所做的,所以在运行回滚查询时使用"results to Text"选项,并保存脚本和输出结果。(当然,如果更改的行太多,这是不实际的)


从select语句更新的另一种方法:

1
2
3
4
UPDATE A
SET A.col = A.col,B.col1 = B.col1
FROM  first_Table AS A
INNER JOIN second_Table AS B  ON A.id = B.id WHERE A.col2 = 'cool'


1
2
3
4
5
6
7
UPDATE TABLE AS a
INNER JOIN table2 AS b
ON a.col1 = b.col1
INNER JOIN ... AS ...
ON ... = ...
SET ...
WHERE ...


在这里整合所有不同的方法。

  • 选择更新
  • 使用公用表表达式更新
  • 合并
  • 示例表结构如下,将从product_k更新到product表。

    产品

    1
    2
    3
    4
    5
    CREATE TABLE [dbo].[Product](
        [Id] [INT] IDENTITY(1, 1) NOT NULL,
        [Name] [nvarchar](100) NOT NULL,
        [Description] [nvarchar](100) NULL
    ) ON [PRIMARY]

    产品制造商

    1
    2
    3
    4
    5
        CREATE TABLE [dbo].[Product_BAK](
            [Id] [INT] IDENTITY(1, 1) NOT NULL,
            [Name] [nvarchar](100) NOT NULL,
            [Description] [nvarchar](100) NULL
        ) ON [PRIMARY]

    1。选择更新

    1
    2
    3
    4
    5
        UPDATE P1
        SET Name = P2.Name
        FROM Product P1
        INNER JOIN Product_Bak P2 ON p1.id = P2.id
        WHERE p1.id = 2

    2。使用公用表表达式更新

    1
    2
    3
    4
    5
    6
    7
    8
        ; WITH CTE AS
        (
            SELECT id, name FROM Product_Bak WHERE id = 2
        )
        UPDATE P
        SET Name = P2.name
        FROM  product P  INNER JOIN CTE P2 ON P.id = P2.id
        WHERE P2.id = 2

    三。合并

    1
    2
    3
    4
    5
        MERGE INTO product P1
        USING Product_Bak P2 ON P1.id = P2.id

        WHEN matched THEN
        UPDATE SET p1.[description] = p2.[description], p1.name = P2.Name;

    在此MERGE语句中,如果在目标中找不到匹配的记录,但源中存在,则可以执行插入操作,请查找语法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        MERGE INTO product P1
        USING Product_Bak P2 ON P1.id = P2.id;

        WHEN matched THEN
        UPDATE SET p1.[description] = p2.[description], p1.name = P2.Name;

        WHEN NOT MATCHED THEN
        INSERT (name, description)
        VALUES(p2.name, P2.description);

    以下解决方案适用于MySQL数据库:

    1
    2
    3
    UPDATE table1 a , table2 b
    SET a.columname = 'some value'
    WHERE b.columnname IS NULL ;


    选项1:使用内部联接:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    UPDATE
        A
    SET
        A.col1 = B.col1,
        A.col2 = B.col2
    FROM
        Some_Table AS A
        INNER JOIN Other_Table AS B
            ON A.id = B.id
    WHERE
        A.col3 = 'cool'

    选项2:共同相关子查询

    1
    2
    3
    4
    5
    6
    7
    8
    UPDATE TABLE
    SET Col1 = B.Col1,
        Col2 = B.Col2
    FROM (
        SELECT ID, Col1, Col2
        FROM other_table) B
    WHERE
        B.ID = TABLE.ID

    1
    2
    3
    4
    5
    UPDATE table1
    SET column1 = (SELECT expression1
                   FROM table2
                   WHERE conditions)
    [WHERE conditions];

    使用SQL Server中另一个表的数据更新一个表时,update语句的语法


    您可以在SQL Server中使用此更新

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    UPDATE
        T1
    SET
       T1.col1 = T2.col1,
       T1.col2 = T2.col2
    FROM
       Table1 AS T1
    INNER JOIN Table2 AS T2
        ON T1.id = T2.id
    WHERE
        T1.col3 = 'cool'

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    DECLARE @tblStudent TABLE (id INT,name VARCHAR(300))
    DECLARE @tblMarks TABLE (std_id INT,std_name VARCHAR(300),subject VARCHAR(50),marks INT)

    INSERT INTO @tblStudent VALUES (1,'Abdul')
    INSERT INTO @tblStudent VALUES(2,'Rahim')

    INSERT INTO @tblMarks VALUES(1,'','Math',50)
    INSERT INTO @tblMarks VALUES(1,'','History',40)
    INSERT INTO @tblMarks VALUES(2,'','Math',30)
    INSERT INTO @tblMarks VALUES(2,'','history',80)


    SELECT * FROM @tblMarks

    UPDATE m
    SET m.std_name=s.name
     FROM @tblMarks AS m
    LEFT JOIN @tblStudent AS s ON s.id=m.std_id

    SELECT * FROM @tblMarks

    像这样;但是您必须确保从开始之后更新表和表是相同的。

    1
    2
    3
    4
    UPDATE TABLE SET col1, col2
    FROM TABLE
    INNER JOIN other_table TABLE.id = other_table.id
    WHERE SQL = 'cool'

    相同的解决方案可以用稍微不同的方式编写,因为我只想在编写了两个表之后设置列。在MySQL中工作。

    1
    2
    3
    4
    UPDATE TABLE t,
    (SELECT col1, col2 FROM other_table WHERE SQL = 'cool' ) o
    SET t.col1 = o.col1, t.col2=o.col2
    WHERE t.id = o.id