关于SQL Server:如何在SQL中使用join执行update语句?

How can I do an UPDATE statement with JOIN in SQL?

我需要使用"父"表中的数据更新SQL Server 2005中的此表,请参见以下内容:

销售

1
2
3
id (INT)
udid (INT)
assid (INT)

UD

1
2
id  (INT)
assid  (INT)

sale.assid包含更新ud.assid的正确值。

什么查询可以做到这一点?我想买一台join,但我不确定是否可行。


语法严格取决于您使用的SQL DBMS。下面是在ansi/iso(aka应该用于任何SQL DBMS)、mysql、SQL Server和Oracle中实现这一点的一些方法。请注意,我建议的ansi/iso方法通常比其他两种方法慢得多,但如果您使用的是MySQL、SQL Server或Oracle以外的SQL DBMS,那么这可能是唯一的方法(例如,如果您的SQL DBMS不支持MERGE

ANSI/ISO:

1
2
3
4
5
6
7
8
9
10
11
UPDATE ud
     SET assid = (
          SELECT sale.assid
          FROM sale
          WHERE sale.udid = ud.id
     )
 WHERE EXISTS (
      SELECT *
      FROM sale
      WHERE sale.udid = ud.id
 );

MySQL:

1
2
3
4
UPDATE ud u
INNER JOIN sale s ON
    u.id = s.udid
SET u.assid = s.assid

SQLServer:

1
2
3
4
5
UPDATE u
SET u.assid = s.assid
FROM ud u
    INNER JOIN sale s ON
        u.id = s.udid

PostgreSQL:

1
2
3
4
UPDATE ud
  SET ud.assid = s.assid
FROM sale s
WHERE ud.id = s.udid;

注意,postgres的FROM子句中不能重复目标表。

神谕:

1
2
3
4
5
6
7
8
UPDATE
    (SELECT
        u.assid AS new_assid,
        s.assid AS old_assid
    FROM ud u
        INNER JOIN sale s ON
            u.id = s.udid) up
SET up.new_assid = up.old_assid

SQLite:

1
2
3
4
5
6
7
8
9
10
11
UPDATE ud
     SET assid = (
          SELECT sale.assid
          FROM sale
          WHERE sale.udid = ud.id
     )
 WHERE RowID IN (
      SELECT RowID
      FROM ud
      WHERE sale.udid = ud.id
 );


这应该在SQL Server中工作:

1
2
3
4
UPDATE ud
SET assid = sale.assid
FROM sale
WHERE sale.udid = id


后格雷斯

1
2
3
4
5
6
7
8
9
UPDATE table1
SET    COLUMN = VALUE
FROM   table2,
       table3
WHERE  table1.column_id = table2.id
       AND table1.column_id = table3.id
       AND table1.COLUMN = VALUE
       AND table2.COLUMN = VALUE
       AND table3.COLUMN = VALUE


标准的SQL方法是

1
2
UPDATE ud
SET assid = (SELECT assid FROM sale s WHERE ud.id=s.id)

在SQL Server上,可以使用联接

1
2
3
4
UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id


PostgreSQL:

1
2
3
4
5
6
7
CREATE TABLE ud (id INTEGER, assid INTEGER);
CREATE TABLE sales (id INTEGER, udid INTEGER, assid INTEGER);

UPDATE ud
SET assid = sales.assid
FROM sales
WHERE sales.id = ud.id;


使用联接多个表简化了更新查询。

1
2
3
4
5
6
7
8
   UPDATE
        first_table ft
        JOIN second_table st ON st.some_id = ft.some_id
        JOIN third_table tt  ON tt.some_id = st.some_id
        .....
    SET
        ft.some_column = some_value
    WHERE ft.some_column = 123456 AND st.some_column = 123456

注意-第一个表、第二个表、第三个表和一些列(如123456)是演示表名、列名和ID。用有效的名称替换它们。


另一个例子就是为什么SQL不能真正移植。

对于MySQL来说:

1
2
3
UPDATE ud, sale
SET ud.assid = sale.assid
WHERE sale.udid = ud.id;

有关详细信息,请阅读多表更新:http://dev.mysql.com/doc/refman/5.0/en/update.html

1
2
3
UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
    [WHERE where_condition]


我在想,最上面一篇文章中的SQL Server可以在Sybase上使用,因为它们都是T-SQL,但不幸的是,它们都不是。

对于Sybase,我发现更新需要在表本身上,而不是别名上:

1
2
3
4
5
UPDATE ud
SET u.assid = s.assid
FROM ud u
    INNER JOIN sale s ON
        u.id = s.udid

Teradata Aster提供了另一种实现目标的有趣方式:

1
2
3
4
5
MERGE INTO ud --what trable should be updated
USING sale -- from what table/relation update info should be taken
ON ud.id = sale.udid --join condition
WHEN MATCHED THEN
    UPDATE SET ud.assid = sale.assid; -- how to update

MySQL

如果您忘记了WHERE子句并将所有条件放在ON表达式中,您将获得最佳性能。

我认为这是因为查询首先必须联接表,然后在此基础上运行WHERE子句,所以如果您可以减少联接所需的量,那么这是获取结果/执行udpate的最快方法。

例子脚本

您有一个用户表。他们可以使用用户名、电子邮件或帐号登录。这些帐户可以是活动的(1)或不活动的(0)。这个表有50000行

然后你有一个用户表可以一次性禁用,因为你发现他们都做了一些不好的事情。然而,这个表有一列,用户名、电子邮件和帐号混合在一起。它还有一个"has-run"指示灯,运行后需要设置为1(真)

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
UPDATE users USER
    INNER JOIN
        blacklist_users BlacklistUser
        ON
        (
            USER.username = BlacklistUser.account_ref
            OR
            USER.email = BlacklistedUser.account_ref
            OR
            USER.phone_number = BlacklistUser.account_ref
            AND
            USER.is_active = 1
            AND
            BlacklistUser.has_run = 0
        )
    SET
        USER.is_active = 0,
        BlacklistUser.has_run = 1;

推理

如果必须仅在或条件上联接,则基本上需要检查每行4次,以查看它是否应该联接,并可能返回更多的行。但是,通过给它更多的条件,如果它们在连接时不满足所有条件,那么它可以"跳过"很多行。

奖金

更具可读性。所有条件都在一个位置,要更新的行在一个位置


下面的语句WITH FROM关键字用于使用联接更新多行

1
2
3
UPDATE users
SET users.DivisionId=divisions.DivisionId
FROM divisions JOIN users ON divisions.Name=users.Division


在MS访问中:

1
2
3
UPDATE ud
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;

1
2
3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID

试试这个,我想这个对你有用

1
2
3
4
5
6
7
8
9
UPDATE ud

SET ud.assid = sale.assid

FROM ud

INNER JOIN sale ON ud.id = sale.udid

WHERE sale.udid IS NOT NULL

对于sqlite,使用rowid属性进行更新:

1
2
3
4
5
UPDATE TABLE SET COLUMN = 'NewValue'
WHERE RowID =
(SELECT t1.RowID FROM TABLE t1
JOIN Table2 t2 ON t1.JoinField = t2.JoinField
WHERE t2.SelectValue = 'FooMyBarPlease');