表被指定两次,既作为'UPDATE'的目标,又作为mysql中数据的单独源

时间:2017-07-07 12:17:55

标签: mysql

我在mysql中有以下查询,我想从 检查分支ID 财务年度类型branch_master 分支机构ID 经理 相等,然后更新状态针对 经理 分支ID 经理 表格

UPDATE manager as m1 
  SET m1.status = 'Y'
  WHERE m1.branch_id IN (
    SELECT m2.branch_id FROM manager as m2 
     WHERE (m2.branch_id,m2.year) IN (
        (
          SELECT DISTINCT branch_id,year 
            FROM `branch_master` 
           WHERE type = 'finance'
        )
     )
  )

但是收到错误

  

表'm1'被指定两次,既作为'UPDATE'的目标又作为a   单独的数据来源

7 个答案:

答案 0 :(得分:54)

这是一个典型的MySQL事物,通常可以通过从派生表中选择来避开,即代替

FROM manager AS m2

使用

FROM (select * from manager) AS m2

完整陈述:

UPDATE manager
SET status = 'Y'
WHERE branch_id IN
(
  select branch_id
  FROM (select * from manager) AS m2
  WHERE (branch_id, year) IN
  (
    SELECT branch_id, year
    FROM branch_master
    WHERE type = 'finance'
  )
);

答案 1 :(得分:1)

尝试:::

UPDATE manager as m1 
SET m1.status = 'Y'
WHERE m1.branch_id IN (
  (SELECT DISTINCT branch_id
  FROM branch_master
  WHERE type = 'finance'))
  AND m1.year IN ((SELECT DISTINCT year
  FROM branch_master 
  WHERE type = 'finance'))

答案 2 :(得分:1)

尝试使用EXISTS运算符:

UPDATE manager as m1 
SET m1.status = 'Y'
WHERE EXISTS (SELECT 1
              FROM (SELECT m2.branch_id             
                    FROM branch_master AS bm
                    JOIN manager AS m2
                    WHERE bm.type = 'finance' AND
                        bm.branch_id = m2.branch_id AND
                        bm.year = m2.year) AS t
              WHERE t.branch_id = m1.branch_id); 

注意:该查询使用@Thorsten建议的其他嵌套级别,作为绕过 Table指定两次错误的方法。

Demo here

答案 3 :(得分:0)

也许不是一个解决方案,但是首先考虑了为什么它不起作用:

从表中读取数据并将数据写入同一表中有些定义不明确。应该以什么顺序读取和写入数据?从同一张表读回时,应考虑新写入的数据吗? MySQL拒绝执行此命令不仅是由于局限性,还因为它不是一项定义明确的任务。

涉及SELECT ... FROM (SELECT * FROM table) AS tmp的解决方案只是将表的全部内容转储到临时表中,然后可以将其用于任何其他外部查询中,例如更新查询。这将强制操作顺序为:首先将所有内容都选择到临时表中,然后然后使用该数据(而不是原始表中的数据)进行更新。

但是,如果所涉及的表很大,那么此临时复制将非常慢。没有索引会加速SELECT * FROM table

我今天可能会过得很慢...但是原始查询与此不相同,哪一个没有问题?

UPDATE manager as m1 
SET m1.status = 'Y'
WHERE (m1.branch_id, m1.year) IN (
      SELECT DISTINCT branch_id,year 
        FROM `branch_master` 
       WHERE type = 'finance'
    )

答案 4 :(得分:0)

我接受的答案存在的问题是创建整个表的副本,但对于我来说这不是一个选择,我尝试执行该表,但几个小时后不得不取消它。

如果您有大量数据,一种非常快速的方法是创建一个临时表:

  1. 创建TMP表

    创建临时表tmp_manager     (branch_id bigint auto_increment主键,      年datetime null);

  2. 填充TMP表

    插入tmp_manager(branch_id,年份) 选择branch_id,年份 来自经理;

  3. 使用连接进行更新

    更新管理器为m,tmp_manager为tmp_m 内部JOIN管理器作为tmp_m.branch_id = man.branch_id上的人 SET状态=“ Y” 其中m.branch_id = tmp_m.branch_id和m.year = tmp_m.year且m.type ='finance';

答案 5 :(得分:0)

正确答案在this SO post中。

这里接受的答案的问题是-正如多次提到的那样-创建整个表的完整副本。这离最佳和最复杂的空间还很远。想法是实现仅用于更新的数据子集,因此在您的情况下将是这样的:

UPDATE manager as m1
SET m1.status = 'Y'
WHERE m1.branch_id IN (
    SELECT * FROM(
        SELECT m2.branch_id FROM manager as m2 
        WHERE (m2.branch_id,m2.year) IN (
            SELECT DISTINCT branch_id,year 
            FROM `branch_master` 
            WHERE type = 'finance')
    ) t
)

基本上,您只是将以前的数据源查询封装在

SELECT * FROM (...) t

答案 6 :(得分:0)

这是迄今为止最快的方法:

{{1}}

请注意,如果是1:n关系,则SET命令将运行多次。在这种情况下,这没问题。但是,如果您有类似“ SET price = price + 5”的信息,则无法使用此构造。