如何从SQL Server中的SELECT更新?

jam*_*ley 3546 sql t-sql sql-server select

SQL Server中,可以insert使用SELECT语句进入表:

INSERT INTO Table (col1, col2, col3)
SELECT col1, col2, col3 
FROM other_table 
WHERE sql = 'cool'
Run Code Online (Sandbox Code Playgroud)

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

UPDATE Table SET col1, col2
SELECT col1, col2 
FROM other_table 
WHERE sql = 'cool'
WHERE Table.id = other_table.id
Run Code Online (Sandbox Code Playgroud)

Rob*_*Day 5159

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'
Run Code Online (Sandbox Code Playgroud)

  • 如果您正在编辑表之间的链接(`SET Table.other_table_id = @ NewValue`),那么将ON语句更改为`ON Table.id = @IdToEdit AND other_table.id = @ NewValue` (14认同)
  • @RogerRay,这个问题是关于Microsoft SQL Server的.不幸的是,各种SQL实现之间的语法可能有所不同. (11认同)
  • 有点相关,我经常喜欢先将我的UPDATE查询编写为SELECT语句,以便在执行之前可以看到将要更新的数据.Sebastian在最近的博客文章中介绍了一种技术:http://sqlity.net/en/2867/update-from-select/ (11认同)
  • 对于 MySQL 数据库:`UPDATE Table_A, Table_B SET Table_A.col1 = Table_B.col1 WHERE Table_A.id = Table_B.table_a_id` (3认同)
  • @CharlesWood是的。我在MySQL中有同样的问题。如果有人知道如何将其实现到MySQL并与所有人共享,那将是很好的。我确定很多人正在寻找MySQL版本解决方案 (2认同)

one*_*hen 748

在SQL Server 2008(或更好)中,使用 MERGE

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;
Run Code Online (Sandbox Code Playgroud)

或者:

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;
Run Code Online (Sandbox Code Playgroud)

  • `MERGE`也可以用于"Upserting"记录; 也就是说,如果匹配记录存在,则为"UPDATE",如果未找到匹配,则"INSERT"新记录 (122认同)
  • 合并错误:http://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ (23认同)
  • MERGE也可用于删除.但要注意MERGE,因为TARGET表不能是远程表. (17认同)
  • 对于我来说,这比同等更新...加入声明快了大约10倍. (16认同)
  • @SimonD:选择任何SQL Server关键字,你会发现错误.你的观点?我打赌有更多的错误(以及更多基本的错误)与`UPDATE`相关而不是'MERGE`,人们刚刚学会了与他们一起生活,他们成为景观的一部分('特征').当"UPDATE"是块上的新孩子时,请考虑博客不存在. (14认同)
  • @SimonD我相信你能在单独的INSERT/UPDATE/DELETE组合中找到类似于这些MERGE"bug"(好......)的问题.一件事 - 如果你想避免最常见的竞争条件,总是在SERIALIZABLE交易中使用MERGE(或使用HOLDLOCK提示).使用INSERT/UPDATE/DELETE进行手动合并相同... (3认同)
  • 可移植性说明:[MERGE](https://en.wikipedia.org/wiki/Merge_(SQL))是ANSI SQL; [UPDATE ... FROM](https://en.wikipedia.org/wiki/Update_(SQL))不是.使用了两者之后,我发现MERGE语义更容易理解 - 我不太可能搞砸MERGE而不是UPDATE ... FROM.因人而异. (3认同)

小智 629

UPDATE table 
SET Col1 = i.Col1, 
    Col2 = i.Col2 
FROM (
    SELECT ID, Col1, Col2 
    FROM other_table) i
WHERE 
    i.ID = table.ID
Run Code Online (Sandbox Code Playgroud)

  • 这将适用于几乎所有DBMS,这意味着学习一次,到处执行.如果这对您而言比性能更重要,您可能更喜欢这个答案,特别是如果您的更新是一次性更正某些数据. (11认同)
  • 到目前为止最简单!但是你错过了内部SELECT的**ID**字段.您需要这个才能使WHERE子句起作用 (7认同)
  • 如果您需要使用第二个表中的聚合来设置第一个表,则可以将聚合放在 select 子查询中,因为您不能执行“SET Table_A.col1 = SUM(Table_B.col1)”(或任何其他聚合函数)。为此,比罗宾·戴的答案更好。 (3认同)

qui*_*ker 273

我会修改罗宾对以下内容的出色答案:

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
)
Run Code Online (Sandbox Code Playgroud)

如果没有WHERE子句,您甚至会影响不需要受影响的行,这可能(可能)导致索引重新计算或实际上不应该触发的触发器.

  • `WHERE EXISTS(SELECT T1.Col1,T1.Col2 EXCEPT SELECT T2.Col1,T2.Col2))`更简洁. (45认同)
  • 这假设没有列可以为空. (7认同)
  • 该语句是否也应该在where子句中包含这两个?(other_table.col1为null且table.col1不为null)或(other_table.col2为null且table.col2不为null) (5认同)
  • 你是对的,我正在手工输入这个例子.我已经在where语句中添加了第三个和第四个子句来处理它. (4认同)
  • 取决于是否要使用源中的空值替换目标中的空值.我经常不这样做.但是,如果你这样做,马丁建立where子句是最好的选择. (4认同)

SQL*_*ace 197

单程

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'
Run Code Online (Sandbox Code Playgroud)


Mar*_*ith 156

尚未提及的另一种可能性是将SELECT语句本身放入CTE然后更新CTE.

;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
Run Code Online (Sandbox Code Playgroud)

这样做的好处是,可以很容易地首先运行SELECT语句以检查结果的完整性,但是如果在源表和目标表中将列命名为相同,则它确实要求您对列进行别名.

这也UPDATE ... FROM与其他四个答案中显示的专有语法具有相同的限制.如果源表位于一对多连接的多个边上,则不确定哪个可能的匹配连接记录将被用于Update(MERGE如果尝试更新,则可以避免引发错误的问题)同一行不止一次).

  • @ShivanRaptor - 它是[Common Table Expression]的首字母缩写词(http://msdn.microsoft.com/en-us/library/ms190766(v = sql.105).aspx).在这种情况下只是一个任意别名. (19认同)
  • 这也适用于多个CTE:`; WITH SomeCompexCTE AS(...),CTEAsAbove AS(SELECT T1.Col1,... FROM T1 JOIN SomeComplexCTE ......)UPDATE CTEAsAbove SET Col1 = _Col1,...` (3认同)
  • 名称CTE有什么意思吗? (2认同)

Adr*_*eil 107

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

UPDATE first_table, second_table
SET first_table.color = second_table.color
WHERE first_table.id = second_table.foreign_id
Run Code Online (Sandbox Code Playgroud)


rag*_*eit 89

使用别名:

UPDATE t
   SET t.col1 = o.col1
  FROM table1 AS t
         INNER JOIN 
       table2 AS o 
         ON t.id = o.id
Run Code Online (Sandbox Code Playgroud)


小智 67

这样做的简单方法是:

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
Run Code Online (Sandbox Code Playgroud)

  • 这不是SQl Server语法,它在SQL Server中不起作用 (20认同)
  • 您的格式更好;另外,使用子选择时,您(和阿德里安)的选择比其他格式更可靠。感谢您发布答案。 (2认同)

Rya*_*yan 56

这可能是执行更新的一个利基理由(例如,主要用于过程),或者对其他人来说可能是显而易见的,但是还应该说明您可以在不使用连接的情况下执行update-select语句(如果是您正在更新的表没有公共字段).

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
Run Code Online (Sandbox Code Playgroud)


efi*_*rat 54

这是另一个有用的语法:

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);
Run Code Online (Sandbox Code Playgroud)

它使用"WHERE EXIST"检查它是否为null.


HLG*_*GEM 48

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

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 
Run Code Online (Sandbox Code Playgroud)


小智 48

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

UPDATE Table1
INNER JOIN Table2
ON Table1.id = Table2.id
SET Table1.col1 = Table2.col1,
    Table1.col2 = Table2.col2
Run Code Online (Sandbox Code Playgroud)


Jas*_*ark 47

在SQL数据库中使用INNER JOIN从SELECT更新

由于这篇文章的回复太多,其中投票率最高,我想我也会在这里提出我的建议.虽然这个问题非常有趣,但我在很多论坛网站上都看到了,并使用INNER JOIN和截图进行了解决方案.

首先,我创建了一个以schoolold命名的表,并插入了几个与其列名相关的记录并执行它.

然后我执行SELECT命令来查看插入的记录.

然后我创建了一个以schoolnew命名的新表,并且类似地执行了上面的操作.

然后,为了查看插入的记录,我执行SELECT命令.

现在,我想在第三和第四行进行一些更改,为了完成此操作,我使用INNER JOIN执行UPDATE命令.

要查看更改,我执行SELECT命令.

你可以看到三和表四的记录schoolold与表容易更换schoolnew使用INNER JOIN与UPDATE语句.


Ale*_*nko 39

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

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
Run Code Online (Sandbox Code Playgroud)


jak*_*zon 39

如果你想加入桌子(这不会经常发生):

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
Run Code Online (Sandbox Code Playgroud)

  • +1但你应该使用相关的别名,如`targett1`和`sourcet1`而不是(或同样)注释. (7认同)

Pரத*_*ீப் 37

更新通过CTE比其他答案更具可读性:

;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
Run Code Online (Sandbox Code Playgroud)


Ric*_*ard 36

如果您使用的是SQL Server,则可以在不指定连接的情况下从另一个表更新一个表,只需从where子句中链接两个.这使得SQL查询更加简单:

UPDATE Table1
SET Table1.col1 = Table2.col1,
    Table1.col2 = Table2.col2
FROM
    Table2
WHERE
    Table1.id = Table2.id
Run Code Online (Sandbox Code Playgroud)


sql*_*ser 22

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

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
Run Code Online (Sandbox Code Playgroud)

样本数据

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
Run Code Online (Sandbox Code Playgroud)


Yam*_*man 22

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)


Abd*_*eez 21

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

  1. 选择更新
  2. 使用公用表表达式进行更新
  3. 合并

示例表结构如下所示,将从Product_BAK更新为Product表.

产品

CREATE TABLE [dbo].[Product](
    [Id] [int] IDENTITY(1, 1) NOT NULL,
    [Name] [nvarchar](100) NOT NULL,
    [Description] [nvarchar](100) NULL
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

Product_BAK

    CREATE TABLE [dbo].[Product_BAK](
        [Id] [int] IDENTITY(1, 1) NOT NULL,
        [Name] [nvarchar](100) NOT NULL,
        [Description] [nvarchar](100) NULL
    ) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

1.选择更新

    update P1
    set Name = P2.Name
    from Product P1
    inner join Product_Bak P2 on p1.id = P2.id
    where p1.id = 2
Run Code Online (Sandbox Code Playgroud)

2.使用公用表表达式进行更新

    ; 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
Run Code Online (Sandbox Code Playgroud)

合并

    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;
Run Code Online (Sandbox Code Playgroud)

在Merge语句中,如果没有在目标中找到匹配的记录,我们可以进行插入,但是在源代码中存在并且请查找语法:

    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);
Run Code Online (Sandbox Code Playgroud)


Bar*_*z X 20

甚至有一个更短的方法,你可能会感到惊讶:

样本数据集:

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');
Run Code Online (Sandbox Code Playgroud)

码:

UPDATE #DEST
SET #DEST.[Desc] = #SOURCE.[Desc]
FROM #SOURCE
WHERE #DEST.[ID] = #SOURCE.[ID];
Run Code Online (Sandbox Code Playgroud)

  • 这与从SELECT更新有什么关系? (2认同)
  • 这是同样的想法,但另一种方法 - 你根本不需要放"select"来实现更新语句中的JOIN和WHERE - 这是SELECT类型的查询,甚至没有编写SELECT (2认同)

小智 19

使用:

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
Run Code Online (Sandbox Code Playgroud)

无论是:

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')
Run Code Online (Sandbox Code Playgroud)

要么:

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
Run Code Online (Sandbox Code Playgroud)

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

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')
Run Code Online (Sandbox Code Playgroud)


Joh*_*ntu 14

在接受的答案中,在:

SET
Table_A.col1 = Table_B.col1,
Table_A.col2 = Table_B.col2
Run Code Online (Sandbox Code Playgroud)

我想补充一下:

OUTPUT deleted.*, inserted.*
Run Code Online (Sandbox Code Playgroud)

我通常做的是将所有内容放在一个支持滚动的事务中并使用"OUTPUT":以这种方式我看到即将发生的一切.当我对自己看到的东西感到满意时,我会改变ROLLBACKCOMMIT.

我通常需要记录我所做的事情,所以"results to Text"当我运行roll-backed查询时我使用该选项并保存脚本和OUTPUT的结果.(当然,如果我改变太多行,这是不切实际的)


小智 13

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

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'
Run Code Online (Sandbox Code Playgroud)

  • _另一种从select语句更新的方法_与其他答案有什么区别?请详细说明你的答案.请记住:一个好的答案**将始终解释所做的事情以及为什么以这种方式完成,不仅对于OP而且对于未来的SO访问者. (4认同)
  • 这个答案出现在低质量审查队列中,可能是因为您没有提供代码的任何解释。如果此代码回答了问题,请考虑添加一些文本来解释答案中的代码。这样,你就更有可能获得更多的支持——并帮助提问者学习新的东西。 (2认同)

Mat*_*een 12

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

UPDATE table1 a , table2 b 
SET a.columname = 'some value' 
WHERE b.columnname IS NULL ;
Run Code Online (Sandbox Code Playgroud)


小智 12

UPDATE table AS a
INNER JOIN table2 AS b
ON a.col1 = b.col1
INNER JOIN ... AS ...
ON ... = ...
SET ...
WHERE ...
Run Code Online (Sandbox Code Playgroud)

  • 此格式适用于MS Access.将JOIN放在最后会出现"语法错误(缺少运算符)"消息.更多示例:https://www.fmsinc.com/microsoftaccess/query/snytax/update-query.html (2认同)

小智 7

UPDATE table1
SET column1 = (SELECT expression1
               FROM table2
               WHERE conditions)
[WHERE conditions];
Run Code Online (Sandbox Code Playgroud)

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


the*_*ng2 7

重要的是要指出,就像其他人一样,MySQLMariaDB使用不同的语法。它还支持非常方便的 USING 语法(与 T/SQL 相比)。INNER JOIN 也是 JOIN 的同义词。因此,原始问题中的查询最好在 MySQL 中实现:

UPDATE
    Some_Table AS Table_A

JOIN
    Other_Table AS Table_B USING(id)

SET
    Table_A.col1 = Table_B.col1,
    Table_A.col2 = Table_B.col2

WHERE
    Table_A.col3 = 'cool'
Run Code Online (Sandbox Code Playgroud)

我还没有在其他答案中看到所问问题的解决方案,因此我花了两美分。 (在 PHP 7.4.0 MariaDB 10.4.10 上测试)


Erf*_*adi 5

您可以使用它来更新 SQL\xc2\xa0Server:

\n
UPDATE\n    T1\nSET\n   T1.col1 = T2.col1,\n   T1.col2 = T2.col2\nFROM\n   Table1 AS T1\nINNER JOIN Table2 AS T2\n    ON T1.id = T2.id\nWHERE\n    T1.col3 = 'cool'\n
Run Code Online (Sandbox Code Playgroud)\n


小智 5

选项1:使用内部联接:

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'
Run Code Online (Sandbox Code Playgroud)

选项2:与公司相关的子查询

UPDATE table 
SET Col1 = B.Col1, 
    Col2 = B.Col2 
FROM (
    SELECT ID, Col1, Col2 
    FROM other_table) B
WHERE 
    B.ID = table.ID
Run Code Online (Sandbox Code Playgroud)