MySQL-基于SELECT查询的UPDATE查询


501

我需要检查(从同一张表中)基于日期时间的两个事件之间是否存在关联。

一组数据将包含某些事件的结束日期时间,另一组数据将包含其他事件的开始日期时间。

如果第一个事件在第二个事件之前完成,那么我想将它们链接起来。

到目前为止,我有:

SELECT name as name_A, date-time as end_DTS, id as id_A 
FROM tableA WHERE criteria = 1


SELECT name as name_B, date-time as start_DTS, id as id_B 
FROM tableA WHERE criteria = 2

然后我加入他们:

SELECT name_A, name_B, id_A, id_B, 
if(start_DTS > end_DTS,'VALID','') as validation_check
FROM tableA
LEFT JOIN tableB ON name_A = name_B

然后,可以基于我的validation_check字段运行带有嵌套SELECT的UPDATE查询吗?


2
我不确定你在问什么?您是否要弄清楚如何使用SQL Select进行更新?
RiddlerDev

Answers:


811

您实际上可以通过以下两种方式之一执行此操作:

MySQL更新联接语法:

UPDATE tableA a
INNER JOIN tableB b ON a.name_a = b.name_b
SET validation_check = if(start_dts > end_dts, 'VALID', '')
-- where clause can go here

ANSI SQL语法:

UPDATE tableA SET validation_check = 
    (SELECT if(start_DTS > end_DTS, 'VALID', '') AS validation_check
        FROM tableA
        INNER JOIN tableB ON name_A = name_B
        WHERE id_A = tableA.id_A)

选择最适合您的那个。


92
第一种形式(与加入更新)将是一个很多比第二更高效。第一个将执行单个联接,而第二个将对tableA的每一行执行选择查询。
ColinM

16
对于第一个示例,您不应该使用内部联接吗?对于没有相应tableB记录的tableA记录,左联接结果是否会把validation_check设置为null?
塞林2014年

3
@Cerin是的,发生在我身上。应该是内部联接!或者只是将其保留为联接。如果没有内部联接,则左侧联接意味着将更新所有tableA记录!这非常危险!
CMCDragonkai

10
感谢您的第一个(y)。虽然这个答案已经超过7年了。我不敢相信为什么没有人说第二个在某些数据库(例如MySQL)中不起作用。您将收到此错误:You can't specify target table ___ for update in FROM clause SQL.sql
Jugali Lakota

1
另外,请注意,直到最近,第一种方法在tableA= 时才不适用于MySQL tableB。您被迫创建一个临时表来存储中间结果。(必须为迁移脚本编写类似的查询)
svvac

301
UPDATE
    `table1` AS `dest`,
    (
        SELECT
            *
        FROM
            `table2`
        WHERE
            `id` = x
    ) AS `src`
SET
    `dest`.`col1` = `src`.`col1`
WHERE
    `dest`.`id` = x
;

希望这对您有用。


5
这是迄今为止最快的查询。编辑:具有22K行的目标和具有4K行的src,完成所需的时间不到1秒,而最高答案超过60秒。
克里斯·德夫

1
是的,这是最快的查询,顺便说一句,您也可以添加WHERE子句
robinmag

1
最快并不总是意味着好,此更新在所有情况下都无法正常工作,实际上,在某些情况下,您将遇到意外行为,这就是为什么不设置条件并且不是
联接的原因

114

在MySQL中很容易:

UPDATE users AS U1, users AS U2 
SET U1.name_one = U2.name_colX
WHERE U2.user_id = U1.user_id

58

如果有人试图将数据从一个数据库更新到另一个数据库,无论他们针对的是哪个表,那么都必须有一些标准来做到这一点。

这对所有级别的人来说都是更好和干净的:

UPDATE dbname1.content targetTable

LEFT JOIN dbname2.someothertable sourceTable ON
    targetTable.compare_field= sourceTable.compare_field
SET
    targetTable.col1  = sourceTable.cola,
    targetTable.col2 = sourceTable.colb, 
    targetTable.col3 = sourceTable.colc, 
    targetTable.col4 = sourceTable.cold 

特拉!效果很好!

基于以上理解,您可以修改设置字段和“启用”条件来进行工作。您还可以执行检查,然后将数据拉入临时表,然后使用上述语法替换表名和列名来运行更新。

希望它能奏效,如果不能让我知道。我会为您写一个确切的查询。


24
UPDATE 
  receipt_invoices dest,
  (
    SELECT 
      `receipt_id`,
      CAST((net * 100) / 112 AS DECIMAL (11, 2)) witoutvat 
    FROM
      receipt 
    WHERE CAST((net * 100) / 112 AS DECIMAL (11, 2)) != total 
      AND vat_percentage = 12
  ) src 
SET
  dest.price = src.witoutvat,
  dest.amount = src.witoutvat 
WHERE col_tobefixed = 1 
  AND dest.`receipt_id` = src.receipt_id ;

希望这对您必须在两个表之间进行匹配和更新的情况有所帮助。


12

我在寻找自己的非常复杂的联接的解决方案时发现了这个问题。这是该问题的更复杂版本的替代解决方案,我认为这可能是有用的。

我需要在活动表中填充product_id字段,其中活动以单位进行编号,单位以级别进行编号(使用字符串?? N标识),以便可以使用SKU(即L1U1A1)识别活动。这些SKU然后存储在另一个表中。

我确定了以下内容以获取activity_id与product_id的列表:-

SELECT a.activity_id, w.product_id 
  FROM activities a 
  JOIN units USING(unit_id) 
  JOIN product_types USING(product_type_id) 
  JOIN web_products w 
    ON sku=CONCAT('L',SUBSTR(product_type_code,3), 'U',unit_index, 'A',activity_index)

我发现这太复杂了,无法合并到mysql的SELECT中,因此我创建了一个临时表,并使用update语句将其加入:

CREATE TEMPORARY TABLE activity_product_ids AS (<the above select statement>);

UPDATE activities a
  JOIN activity_product_ids b
    ON a.activity_id=b.activity_id 
  SET a.product_id=b.product_id;

我希望有人觉得这有用


在多线程环境中,两个查询可能不会给出一致的结果。
唐纳德

7
UPDATE [table_name] AS T1,
      (SELECT [column_name] 
        FROM [table_name] 
        WHERE [column_name] = [value]) AS T2 
  SET T1.[column_name]=T2.[column_name] + 1
WHERE T1.[column_name] = [value];

4

您可以像这样使用内部联接更新另一个表中的值

UPDATE [table1_name] AS t1 INNER JOIN [table2_name] AS t2 ON t1.column1_name] = t2.[column1_name] SET t1.[column2_name] = t2.column2_name];

请按照此处了解如何使用此查询http://www.voidtricks.com/mysql-inner-join-update/

或者您可以使用select作为子查询来执行此操作

UPDATE [table_name] SET [column_name] = (SELECT [column_name] FROM [table_name] WHERE [column_name] = [value]) WHERE [column_name] = [value];

查询在这里详细解释http://www.voidtricks.com/mysql-update-from-select/


4

您可以使用:

UPDATE Station AS st1, StationOld AS st2
   SET st1.already_used = 1
 WHERE st1.code = st2.code

3

对于同一张桌子,

UPDATE PHA_BILL_SEGMENT AS PHA,
     (SELECT BILL_ID, COUNT(REGISTRATION_NUMBER) AS REG 
       FROM PHA_BILL_SEGMENT
        GROUP BY REGISTRATION_NUMBER, BILL_DATE, BILL_AMOUNT
        HAVING REG > 1) T
    SET PHA.BILL_DATE = PHA.BILL_DATE + 2
 WHERE PHA.BILL_ID = T.BILL_ID;

1

我在一个表本身中存在重复条目的问题。以下是为我工作的方法。@sibaz也提倡它。

最后,我使用以下查询解决了该问题:

  1. 选择查询保存在临时表中

    IF OBJECT_ID(N'tempdb..#New_format_donor_temp', N'U') IS NOT NULL
        DROP TABLE #New_format_donor_temp;
    
    select *
    into #New_format_donor_temp
    from DONOR_EMPLOYMENTS
    where DONOR_ID IN (
      1, 2
    )
    
    -- Test New_format_donor_temp
    -- SELECT *
    -- FROM #New_format_donor_temp;
  2. 临时表已加入更新查询中。

    UPDATE de
    SET STATUS_CD=de_new.STATUS_CD, STATUS_REASON_CD=de_new.STATUS_REASON_CD, TYPE_CD=de_new.TYPE_CD
    FROM DONOR_EMPLOYMENTS AS de
      INNER JOIN #New_format_donor_temp AS de_new ON de_new.EMP_NO = de.EMP_NO
    WHERE
      de.DONOR_ID IN (
        3, 4
    )

我对SQL不太有经验,请告诉您任何更好的方法。

以上查询是针对MySql服务器的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.