假设我有三个表格,其中包含以下数据:
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。
我的问题是:
USING
编写查询C?我可以吗?USING
基本上使用ON
中提到的当前表格和表格FROM
进行了USING
吗?JOIN
在使用隐式FROM
且多个表位于{{1}}时会做什么?答案 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)
是的,你可以使用嵌套连接:
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
没有。 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!
再次引用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一起使用。它将使用m
与r
加入movie_id
, m
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}}