ver*_*ter 8 sql subquery outer-join
我正在通过GalaXQL教程学习SQL.
我无法弄清楚以下问题(练习12):
使用"starname","startemp","planetname"和"planettemp"列生成明星ID低于100的星列表.该列表应包含所有星号,未知数据填写为NULL.像往常一样,这些价值观是虚构的.用((class + 7)*强度)*1000000计算恒星的温度,并根据恒星的温度减去50倍轨道距离计算行星的温度.
当您有需要连接在一起的子查询项"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
Run Code Online (Sandbox Code Playgroud)
这是数据库架构(抱歉,由于低代表而无法发布图像文件):
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);
Run Code Online (Sandbox Code Playgroud)
Clo*_*use 15
让我们慢慢建立起来.
首先,让我们看看如何获取有关星星的信息:
SELECT name AS starName, (class + 7) * intensity * 1000000 AS starTemp
FROM Stars
WHERE starId < 100
Run Code Online (Sandbox Code Playgroud)
(这应该看起来很熟悉!)
我们得到一个starId小于100 的所有星星(该WHERE子句)的列表,抓住名称并计算温度.此时,我们不需要消除对源的歧义.
接下来,我们需要添加行星信息.怎么样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
Run Code Online (Sandbox Code Playgroud)
该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
Run Code Online (Sandbox Code Playgroud)
......我们有所有的星星回来了,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
Run Code Online (Sandbox Code Playgroud)
...除了在大多数RDBMS上,您将收到声明系统无法找到的语法错误starTemp.这是怎么回事?问题是新的列别名(name)在语句的一部分运行之后才会(通常)可用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
Run Code Online (Sandbox Code Playgroud)
(请注意,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
Run Code Online (Sandbox Code Playgroud)
是的,这看起来就像是我写的.应该基本上适用于任何RDBMS.
请注意,括号中Stars.starTemp - (50 * Planets.orbitDistance)仅为了读者的清晰度,如果删除它们,数学的含义将保持不变.无论您如何了解运算符优先级规则,在混合运算时始终都要加上括号.当处理ORs和ANDs in JOIN和WHERE条件时,这变得特别有益- 许多人忘记将要实施什么.
另请注意,隐式连接语法(逗号分隔FROM子句)通常被认为是不好的做法,或者在某些平台上完全弃用(查询仍然会运行,但数据库可能会骂你).它也使某些事情 - 比如LEFT JOINs - 难以做到,并增加了意外破坏自己的可能性.所以,请避免它.
SELECT * FROM (SELECT [...]) as Alias1
LEFT OUTER JOIN
(SELECT [...]) as Alias2
ON Alias1.id = Alias2.id
Run Code Online (Sandbox Code Playgroud)