GalaXQLチュートリアルを通じてSQLを学習しています。
次の質問がわかりません(演習12)。
列が「starname」、「startemp」、「planetname」、および「planettemp」で、スターIDが100未満のスターのリストを生成します。リストにはすべての星があり、不明なデータはNULLで埋められています。これらの値は、いつものように架空のものです。 ((class + 7)* intensity)* 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
データベーススキーマは次のとおりです(申し訳ありませんが、担当者が少ないため画像ファイルを投稿できません)。
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
句)を取得し、名前を取得して温度を計算します。この時点では、ソースへの明確な参照は必要ありません。
次に、惑星情報を追加する必要があります。 _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
_によってのみ星少なくとも1つの惑星が報告されます。しかし、惑星のない星を報告する必要があります!では、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
(かつ1回だけ表示)になります。これまでのところ良い!
次に、惑星の温度を追加する必要があります。シンプルであるべきです:
_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
を見つけられないことを示す構文エラーが発生します。どうしたの?問題は、afterステートメントの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 mayは実際にはstarTemp
の計算を行ごとに1回だけ実行するのに十分スマートですが、この場合、このコンテキストでは2回記述する必要があります)。
まあ、それは少し面倒ですが、うまくいきます。必要に応じて、両方の参照を変更することを忘れないでください...
ありがたいことに、この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
およびAND
条件でJOIN
sおよびWHERE
sを処理する場合に特に有益になります。多くの人は、何が影響を受けるか分からなくなります。
また、暗黙的な結合構文(コンマ区切りのFROM
句)は、一般に悪い習慣と見なされているか、一部のプラットフォームでは完全に非推奨である(クエリは引き続き実行されますが、dbが君は)。また、_LEFT JOIN
_ sなどの特定のことを行うことが困難になり、誤って自分を妨害する可能性が高くなります。ですから、避けてください。
SELECT * FROM (SELECT [...]) as Alias1
LEFT OUTER JOIN
(SELECT [...]) as Alias2
ON Alias1.id = Alias2.id
WITH(
SELECT
stars.name AS starname, ((star.class+7)*star.intensity)*1000000) AS startemp,
stars.starid
FROM
stars
) AS star_temps
SELECT
planets.name AS planetname, (startemp-50*planets.orbitdistance) AS planettemp
star_temps.starname, star_temps.startemp
FROM
star_temps LEFT OUTER JOIN planets USING (star_id)
WHERE
star_temps.starid < 100;
または、サブクエリを作成して(共通のテーブル式を使用しました)、次に示すように同じタスクを実行できます。
SELECT
planets.name AS planetname, (startemp-50*planets.orbitdistance) AS planettemp
star_temps.starname, star_temps.startemp
FROM
(SELECT
stars.name AS starname, ((star.class+7)*star.intensity)*1000000) AS startemp,
stars.starid
FROM
stars
) AS star_temps
LEFT OUTER JOIN planets USING (star_id)
WHERE
star_temps.starid < 100;