sql - LEFT OUTER JOIN 与子查询语法

标签 sql subquery outer-join

我正在通过 GalaXQL 教程学习 SQL。

我想不通以下问题(练习 12):

Generate a list of stars with star ids below 100 with columns "starname", "startemp", "planetname", and "planettemp". The list should have all stars, with the unknown data filled out with NULL. These values are, as usual, fictional. Calculate the temperature for a star with ((class+7)*intensity)*1000000, and a planet's temperature is calculated from the star's temperature minus 50 times orbit distance.



当您需要将子查询项“AS”连接在一起时,编写 LEFT OUTER JOIN 查询的语法是什么?

这是我所拥有的:
SELECT stars.name AS starname, startemp, planets.name AS planetname, planettemp 
FROM stars, planets 
LEFT OUTER JOIN (SELECT ((stars.class + 7) * stars.intensity) * 1000000 AS startemp 
                 FROM stars) 
             ON stars.starid < 100 = planets.planetid 
LEFT OUTER JOIN (SELECT (startemp - 50 * planets.orbitdistance) AS planettemp 
                 FROM planets) 
             ON stars.starid < 100

这是数据库架构(抱歉,由于代表低,无法发布图像文件):
CREATE TABLE stars (starid INTEGER PRIMARY KEY,
                    name TEXT,
                    x DOUBLE NOT NULL,
                    y DOUBLE NOT NULL,
                    z DOUBLE NOT NULL,
                    class INTEGER NOT NULL,
                    intensity DOUBLE NOT NULL);

CREATE TABLE hilight (starid INTEGER UNIQUE);

CREATE TABLE planets (planetid INTEGER PRIMARY KEY,
                      starid INTEGER NOT NULL,
                      orbitdistance DOUBLE NOT NULL,
                      name TEXT,
                      color INTEGER NOT NULL,
                      radius DOUBLE NOT NULL);

CREATE TABLE moons (moonid INTEGER PRIMARY KEY,
                    planetid INTEGER NOT NULL,
                    orbitdistance DOUBLE NOT NULL,
                    name TEXT,
                    color INTEGER NOT NULL,
                    radius DOUBLE NOT NULL);

CREATE INDEX planets_starid ON planets (starid);
CREATE INDEX moons_planetid ON moons (planetid);

最佳答案

让我们慢慢建立它。

首先,让我们看看仅获取有关星星的信息:

SELECT name AS starName, (class + 7) * intensity * 1000000 AS starTemp 
FROM Stars
WHERE starId < 100

(这应该看起来很熟悉!)
我们得到了所有星星的列表 starId小于 100(WHERE 子句),抓取名称并计算温度。在这一点上,我们不需要对 source 的消除歧义引用。

接下来,我们需要添加行星信息。怎么样 INNER JOIN (注意实际的关键字 INNER 是可选的)?
SELECT Stars.name as starName, (Stars.class + 7) * Stars.intensity * 1000000 AS starTemp,
       Planets.name as planetName
FROM Stars
INNER JOIN Planets
        ON Planets.starId = Stars.starId
WHERE Stars.starId < 100
ON条款正在使用 = (等于)将行星与它们绕行的恒星连接起来的条件;否则,我们会说它们绕着不止一颗恒星运行,这是非常不寻常的!每颗恒星都会针对它所拥有的每颗行星列出一次,但这是意料之中的。

...除了现在我们有一个问题:我们第一次查询中的一些星星消失了! (INNER) JOIN只造成星星至少有一颗行星 被举报。但是我们仍然需要报告没有任何行星的恒星!那么 LEFT (OUTER) JOIN 怎么样? ?
SELECT Stars.name as starName, (Stars.class + 7) * Stars.intensity * 1000000 AS starTemp,
       Planets.name as planetName
FROM Stars
LEFT JOIN Planets
       ON Planets.starId = Stars.starId
WHERE Stars.starId < 100

......我们让所有的星星都回来了,planetName正在 null (并且只出现一次)如果该恒星没有行星。目前很好!

现在我们需要添加行星温度。应该很简单:
SELECT Stars.name as starName, (Stars.class + 7) * Stars.intensity * 1000000 AS starTemp,
       Planets.name as planetName, starTemp - (50 * Planets.orbitDistance) as planetTemp
FROM Stars
LEFT JOIN Planets
       ON Planets.starId = Stars.starId
WHERE Stars.starId < 100

...除了在大多数 RDBMS 上,您会收到一个语法错误,指出系统找不到 starTemp .这是怎么回事?问题是新列别名(名称)在 之前(通常)不可用。后 SELECT语句的一部分运行。这意味着我们需要再次进行计算:
SELECT Stars.name as starName, (Stars.class + 7) * Stars.intensity * 1000000 AS starTemp,
       Planets.name as planetName, 
       ((Stars.class + 7) * Stars.intensity * 1000000) - (50 * Planets.orbitDistance) as planetTemp
FROM Stars
LEFT JOIN Planets
       ON Planets.starId = Stars.starId
WHERE Stars.starId < 100

(请注意,db 实际上可能足够聪明,可以每行仅执行一次 starTemp 计算,但在编写时,您必须在此上下文中提及两次)。
嗯,这有点乱,但它有效。希望您会记得在必要时更改两个引用...

谢天谢地,我们可以移动 Stars将其部分转换为子查询。我们只需要列出 starTemp 的计算一次!
SELECT Stars.starName, Stars.starTemp,
       Planets.name as planetName, 
       Stars.starTemp - (50 * Planets.orbitDistance) as planetTemp
FROM (SELECT starId, name AS starName, (class + 7) * intensity * 1000000 AS starTemp 
      FROM Stars
      WHERE starId < 100) Stars
LEFT JOIN Planets
       ON Planets.starId = Stars.starId

是的,这看起来就像我要写的那样。基本上应该适用于任何 RDBMS。

注意Stars.starTemp - (50 * Planets.orbitDistance)中的括号只是为了让读者清楚起见,如果删除它们,数学的含义将保持不变。不管您对运算符优先级规则有多了解,在混合运算时总是放在括号中。这在处理 OR 时特别有用。 s 和 AND s 在 JOINWHERE条件 - 许多人忘记了将要发生的事情。
另请注意,隐式连接语法(逗号分隔的 FROM 子句)通常被认为是不好的做法,或者在某些平台上被彻底弃用(查询仍会运行,但数据库可能会骂你)。它还可以制作某些东西 - 比如 LEFT JOIN s - 很难做到,并增加了意外破坏自己的可能性。所以请避免它。

关于sql - LEFT OUTER JOIN 与子查询语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23851976/

相关文章:

mysql - 太多的子查询会导致内部服务器错误500吗?

java - 为什么在方法内声明的变量如果要在同一方法内定义的内部类中使用,则需要将其声明为final?

mysql - SQL根据两个用户获取特定线程

mysql - 刷新和锁定 RDS Mysql 数据库中的表所需的权限

MYSQL子查询性能不一致

mysql - 分组依据将最旧和最新的日期放入一行

MySQL 连接导致重复

sql-server - SQL Server 条件联接

sql - 删除重复行 SQL 服务器

sql - 通过 SQL 进行股票交易系统计算