加入两个以上表时USING和ON之间的区别

时间:2014-10-27 21:51:13

标签: mysql sql join

假设我有三个表格,其中包含以下数据:

CREATE TABLE movies (
  movie_id INT,
  movie_name VARCHAR(255),
  PRIMARY KEY (movie_id)
);
CREATE TABLE movie_ratings (
  movie_rating_id INT,
  movie_id INT,
  rating_value TINYINT,
  PRIMARY KEY (movie_rating_id),
  KEY movie_id (movie_id)
);
CREATE TABLE movie_actors (
  movie_actor_id INT,
  movie_id INT,
  actor_id INT,
  PRIMARY KEY (movie_actor_id),
  KEY movie_id (movie_id)
);
INSERT INTO movies VALUES (1, 'Titanic'),(2,'Star Trek');
INSERT INTO movie_ratings VALUES (1,1,5),(2,1,4),(3,1,5);
INSERT INTO movie_actors VALUES (1,1,2),(2,2,2);

如果我想获得每部电影的平均评分和演员数量,我可以使用JOINs执行此操作:

SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r ON m.movie_id = r.movie_id
LEFT JOIN movie_actors a ON m.movie_id = a.movie_id
GROUP BY m.movie_id;

让我们调用该查询A.查询A可以用USING重写:

SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r USING (movie_id)
LEFT JOIN movie_actors a USING (movie_id)
GROUP BY m.movie_id;

我们称之为查询B.

这两个查询都返回1为电影'星际迷航'的numActors。所以让我们稍微修改一下这个查询:

SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r ON m.movie_id = r.movie_id
LEFT JOIN movie_actors a ON r.movie_id = a.movie_id
GROUP BY m.movie_id;

让我们调用此查询C.而不是m.movie_id = a.movie_id我正在做r.movie_id = a.movie_id。对于查询C,numActors为0。

我的问题是:

  1. 如何使用USING编写查询C?我可以吗?
  2. USING基本上使用ON中提到的当前表格和表格FROM进行了USING吗?
  3. 如果对#2的回答是肯定的,那么JOIN在使用隐式FROM且多个表位于{{1}}时会做什么?

4 个答案:

答案 0 :(得分:3)

如果两个表中的列名相同,那么是,您可以使用USING()

换句话说,这个:

SELECT movie_name, AVG(rating_value) AS averageRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings r ON m.movie_id = r.movie_id
LEFT JOIN movie_actors a ON m.movie_id = a.movie_id
GROUP BY m.movie_id;

与:

相同
SELECT movie_name, AVG(rating_value) AS averageRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN movie_ratings USING (movie_id)
LEFT JOIN movie_actors USING (movie_id)
GROUP BY movie_id;

就模棱两可而言,这里不会有任何歧视。当movie_id相等时,它将连接表。在select语句中,您将拉出movie_name,它只存在于一列中。

但是,如果你这样说:

SELECT movie_id, AVG(rating_value) AS averageRating, COUNT(actor_id) AS numActors

MySQL会说有错误,因为无法解析movie_id,因为它不明确。要解决这种歧义,您只需确保在选择movie_id时使用表别名或名称。

这是一个有效的选择语句:

SELECT m.movie_id, AVG(rating_value) AS averageRating, COUNT(actor_id) AS numActors

这不会引发任何错误。

我想评论一下,我预见到这里会有一些危险。如果您使用所有这些表保留连接影片,则可能会收到空值。如果movie_id 1没有任何评级,则AVG(rating_value)将返回null。对于COUNT(actor_id),你不会遇到这个问题,因为这只会返回0.我不知道这是否会让你烦恼,但要注意该列可能会返回null。

我在MySQL工作台中构建了示例表,我无法让SQL Fiddle工作来向您展示,但如果您想查看我创建的数据,请告诉我,我将编辑该问题。

答案 1 :(得分:2)

没有歧义,因为USING适用于连接中的表,所以此查询

SELECT movie_name, AVG(rating_value), COUNT(actor_id)
FROM movies m
LEFT JOIN movie_ratings r USING (movie_id)
LEFT JOIN movie_actors a USING (movie_id)
GROUP BY m.movie_id;

几乎等同于具有内部联接的那个,除了movie_id列应该只在结果中出现一次,而不是在inner join情况下出现三次。

请参阅此示例以了解列消除:http://ideone.com/qMj5XK(使用SQLite我认为,SQL Fiddle不起作用,但MySQL应该以相同的方式运行)。

答案 2 :(得分:2)

1。可以使用USING来重写C吗?

是的,你可以使用嵌套连接:

SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors
FROM movies m
LEFT JOIN (
  movie_ratings r 
  LEFT JOIN movie_actors a USING (movie_id)
) USING (movie_id)
GROUP BY m.movie_id

2。 USING基本上是使用FROM?

中提到的当前表和表进行ON

没有。 MySQL Documentation说:

  

多路自然连接的评估以一种非常重要的方式不同,它影响NATURAL或USING连接的结果,并且可能需要查询重写。假设你有三个表t1(a,b),t2(c,b)和t3(a,c),每个表都有一行:t1(1,2),t2(10,2)和t3( 7,10)。假设你在三个表上都有这个NATURAL JOIN:

     

SELECT ... FROM t1 NATURAL JOIN t2 NATURAL JOIN t3;

     

以前,第二个连接的左操作数被认为是t2,而它应该是嵌套连接(t1 NATURAL JOIN t2)。结果,仅在t2中检查t3的列的公共列,并且如果t3具有带t1的公共列,则这些列不用作等连接列。因此,先前,前面的查询被转换为以下equi-join:

     

SELECT ... FROM t1,t2,t3     在哪里t1.b = t2.b AND t2.c = t3.c;

所以基本上,在旧版本的MySQL中,你的查询B与查询A不同,而是作为查询C!

3。当使用隐式JOIN并且多个表位于FROM?

时,USING会做什么

再次引用MySQL Documentation

  

以前,逗号运算符(,)和JOIN都具有相同的优先级,因此连接表达式t1,t2 JOIN t3被解释为((t1,t2)JOIN t3)。现在JOIN具有更高的优先级,因此表达式被解释为(t1,(t2 JOIN t3))。此更改会影响使用ON子句的语句,因为该子句只能引用连接操作数中的列,并且优先级的更改会更改这些操作数的解释。

所有关于加入顺序和优先顺序。因此,基本上t1, t2 JOIN t3 USING (x)首先t2 JOIN t3 USING(x)t1加入{{1}}。

答案 3 :(得分:1)

  

如何使用USING编写查询C?我可以吗?

与jpw一样,回答,您可以将USING与查询C一起使用。它将使用mr加入movie_idm a movie_id也使用USING。事实上,使用MySQL的USING与SQL 2003标准保持一致。

  

USING实际上是使用当前表和表进行ON   FROM中提到过吗?

FROM正在使用当前表和SELECT子句中提到的表进行ON。唯一的区别是如果在USING子句中使用星号,那么您将要结束的数字列。 FROM tableA, tableB的Oracle documentation比MySQL文档更有帮助。

  

如果#2的答案是肯定的,那么当隐含时,USING会做什么   使用JOIN并且FROM?

中有多个表

您可以亲自尝试,但我很确定它不会使用隐式联接(USING)。这可能是应该避免隐式连接的另一个原因。

此外,numActors只能与显式连接一起使用,这意味着混合了显式和隐式连接的非常尴尬的查询。你可能想要避免的事情。

修改:

顺便说一句,SELECT m.movie_name, AVG(rating_value) AS avgRating, COUNT(actor_id) AS numActors FROM movies m LEFT JOIN movie_ratings r ON m.movie_id = r.movie_id LEFT JOIN movie_actors a ON m.movie_id = a.movie_id -- Instead of r.movie_id = a.movie_id GROUP BY m.movie_id; 在查询C中为0,因为您的连接不正确。事实上,如果没有电影评级,那么没有演员!如果你修复了它,你应该得到与查询B相同的结果。

{{1}}