有时候,我们可以根据某个数据表里数据行是否在另一个数据表里有匹配来删除它们,这很有用。类似地,用一个数据表里的数据行的内容去更新另一个数据表也很有用。本节讨论如何完成涉及多个数据表的DELETE和UPDATE操作。联结概念在用来完成这些操作的语句里扮演着极其重要的角色,这要求你对前面2.8节里讨论的内容有透彻的理解。

  对于只涉及单个数据表的DELETE和UPDATE操作,被引用的数据列都来自同一个数据表,不需要使用数据表的名字对数据列的名字进行限定。比如说,如果要从数据表t里把id值大于100的数据行全部删掉,可以编写如下所示的语句:

  DELETE FROM t WHERE id > 100;

  如果需要根据某给定数据表里数据行与另一个数据表里的数据行之间的关系(而不是根据其自身的属性)来删除它们,你该怎么办?比如说,如果要从数据表t里把其id值可以在另一个数据表t2里找到的数据行删掉,该怎么办?

  在编写一个涉及多个数据表的DELETE语句时,要把所涉及的数据表在FROM子句里全部列出来并把用来匹配各有关数据行(它们来自多个数据表)的检索条件写在WHERE子句里。下面这条语句将从数据表t1里把其id值可以在另一个数据表t2里找到的数据行全部删掉:

  DELETE t1 FROM t1 INNER JOIN t2 ON t1.id = t2.id;

请注意,如果某个数据列的名字出现在了多个数据表里,有可能导致歧义问题,需要用数据表的名字对它加以限定。

  DELETE语句有一种语法可以让我们一次删除多个数据表里的数据行。如果你想从两个数据表里把id值相匹配的数据行都删掉,必须在DELETE关键字的后面写出两个数据表的名字:

  DELETE t1, t2 FROM t1 INNER JOIN t2 ON t1.id = t2.id;

  如果你想删除的是不匹配的数据行,又该怎么办?在涉及多个数据表的DELETE语句里可以使用允许用在SELECT语句里的任何一种联结操作,所以我们可以按照编写一条从多个数据表选取不匹配数据行的SELECT语句的思路去思考。这通常都会归结到是选用LEFT JOIN还是选用RIGHT JOIN上。比如说,如果要从数据表t1里把在数据表t2里没有匹配的数据行找出来,你应该会写出一条如下所示的SELECT语句:

  SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL;

  同样,从数据表t1找出并删除那些数据行的DELETE语句也要用到一个LEFT JOIN操作:

  DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL;

  MySQL还支持另一种涉及多个数据表的DELETE语法。这种语法使用一个FROM子句来列出将从中删除有关数据行的数据表,使用一个USING子句来联结各有关数据表以确定哪些数据行需要被删除。前面那几条涉及多个数据表的DELETE语句可以用这种语法改写为如下所示的样子:

  DELETE FROM t1 USING t1 INNER JOIN t2 ON t1.id = t2.id; 
  DELETE FROM t1, t2 USING t1 INNER JOIN t2 ON t1.id = t2.id; 
  DELETE FROM t1 USING t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL; 

  编写涉及多个数据表的UPDATE语句的基本步骤与编写涉及多个数据表的DELETE语句的很相似。同样需要列出所涉及的全部数据表,同样需要用数据表的名字对数据列的名字进行必要的限定。我们来看一个例子。假设2008年9月23日的测试里有一个问题是所有学生都没有答对的,而你后来发现这是因为你的标准答案有错误。于是,你决定给每位学生的考试成绩加上一分。下面这条涉及多个数据表的UPDATE语句可以完成这个工作:

  UPDATE score, grade_event SET scorescore.score = score.score + 1 
  WHERE score.event_id = grade_event.event_id 
  AND grade_event.date ='2008-09-23' AND grade_event.category = 'Q'; 

  具体到这个问题,你也可以用一个基于子查询的单数据表更新操作来达到同样的目的:

  UPDATE score SET scorescore = score + 1  
  WHERE event_id = (SELECT event_id FROM grade_event  
  WHERE date = '2008-09-23' AND category = 'Q'); 

  但其他类型的更新操作能不能用子查询来完成不一定了。比如说,假设你不仅需要根据另一个数据表的内容来确定应该刷新某给定数据表里的哪些数据行,还需要把另一个数据表的数据列值复制到这个数据表里。下面这条语句将把符合条件的t1.a复制到t2.a,而需要满足的条件是数据行有匹配的id数据列值:

  UPDATE t1, t2 SET t2.a = t1.a WHERE t2.id = t1.id;

  如果是对InnoDB数据表进行多数据表删除和刷新操作,你不必非得使用刚才介绍的语法。更好的办法是在数据表之间建立一个外键关系并给它加上ON DELETE CASCADE或ON UPDATE CASCADE约束条件。