PostgreSQLのクエリの概要
序章
データベースは、多くのWebサイトやアプリケーションの重要なコンポーネントであり、インターネットを介してデータを保存および交換する方法の中核を成しています。 データベース管理の最も重要な側面の1つは、アドホックベースであろうと、アプリケーションにコード化されたプロセスの一部であろうと、データベースからデータを取得する方法です。 データベースから情報を取得する方法はいくつかありますが、最も一般的に使用される方法の1つは、コマンドラインからクエリを送信することによって実行されます。
リレーショナルデータベース管理システムでは、queryはテーブルからデータを取得するために使用される任意のコマンドです。 構造化照会言語(SQL)では、ほとんどの場合、照会はSELECT
ステートメントを使用して行われます。
このガイドでは、SQLクエリの基本的な構文と、より一般的に使用される関数と演算子のいくつかについて説明します。 また、PostgreSQLデータベースのサンプルデータを使用してSQLクエリを作成する練習も行います。
PostgreSQL は、しばしば「Postgres」と短縮され、オブジェクト指向アプローチを備えたリレーショナルデータベース管理システムです。つまり、情報をPostgreSQLスキーマのオブジェクトまたはクラスとして表すことができます。 PostgreSQLは標準SQLと緊密に連携していますが、他のリレーショナルデータベースシステムにはない機能もいくつか含まれています。
前提条件
一般に、このガイドに示されているコマンドと概念は、SQLデータベースソフトウェアを実行しているLinuxベースのオペレーティングシステムで使用できます。 ただし、PostgreSQLを実行しているUbuntu18.04サーバーを念頭に置いて特別に作成されています。 これを設定するには、次のものが必要です。
- sudo権限を持つroot以外のユーザーがいるUbuntu18.04マシン。 これは、Ubuntu18.04の初期サーバーセットアップガイドを使用してセットアップできます。
- マシンにインストールされているPostgreSQL。 これを設定するためのヘルプについては、 Ubuntu18.04にPostgreSQLをインストールして使用する方法に関するガイドの「PostgreSQLのインストール」セクションに従ってください。
この設定が整ったら、チュートリアルを開始できます。
サンプルデータベースの作成
SQLでクエリを作成する前に、まずデータベースといくつかのテーブルを作成し、次にこれらのテーブルにサンプルデータを入力します。 これにより、後でクエリを作成し始めるときに、実践的な経験を積むことができます。
このガイド全体で使用するサンプルデータベースについて、次のシナリオを想像してください。
あなたとあなたの友人の何人かは皆、お互いにあなたの誕生日を祝います。 毎回、グループのメンバーは地元のボウリング場に向かい、フレンドリーなトーナメントに参加します。その後、全員があなたの場所に向かい、誕生日の人の好きな食事を準備します。
この伝統がしばらく続いているので、あなたはこれらのトーナメントからの記録を追跡し始めることに決めました。 また、夕食の計画を簡単にするために、友達の誕生日とお気に入りのメインディッシュ、サイドディッシュ、デザートの記録を作成することにしました。 この情報を物理的な元帳に保持するのではなく、PostgreSQLデータベースに記録してデータベーススキルを行使することにします。
まず、postgresスーパーユーザーとしてPostgreSQLプロンプトを開きます。
- sudo -u postgres psql
注: Ubuntu 18.04 へのPostgreSQLのインストールに関する前提条件のチュートリアルのすべての手順を実行した場合は、PostgreSQLインストールの新しい役割を構成している可能性があります。 この場合、sammy
を自分のユーザー名に置き換えて、次のコマンドを使用してPostgresプロンプトに接続できます。
- sudo -u sammy psql
次に、以下を実行してデータベースを作成します。
- CREATE DATABASE birthdays;
次に、次のように入力してこのデータベースを選択します。
- \c birthdays
次に、このデータベース内に2つのテーブルを作成します。 最初のテーブルを使用して、ボウリング場での友達の記録を追跡します。 次のコマンドは、tourneys
というテーブルを作成し、各友達のname
、勝ったトーナメントの数(wins
)、すべての列を示します。時間best
スコア、および彼らが着用するボウリングシューズのサイズ(size
):
- CREATE TABLE tourneys (
- name varchar(30),
- wins real,
- best real,
- size real
- );
CREATE TABLE
コマンドを実行して列見出しを入力すると、次の出力が表示されます。
OutputCREATE TABLE
tourneys
テーブルにいくつかのサンプルデータを入力します。
- INSERT INTO tourneys (name, wins, best, size)
- VALUES ('Dolly', '7', '245', '8.5'),
- ('Etta', '4', '283', '9'),
- ('Irma', '9', '266', '7'),
- ('Barbara', '2', '197', '7.5'),
- ('Gladys', '13', '273', '8');
次の出力が表示されます。
OutputINSERT 0 5
これに続いて、同じデータベース内に別のテーブルを作成します。このテーブルを使用して、友達のお気に入りの誕生日の食事に関する情報を保存します。 次のコマンドは、dinners
という名前のテーブルを作成します。このテーブルには、各友達のname
、birthdate
、お気に入りのentree
、好みのside
皿、そして彼らのお気に入りのdessert
:
- CREATE TABLE dinners (
- name varchar(30),
- birthdate date,
- entree varchar(30),
- side varchar(30),
- dessert varchar(30)
- );
同様に、このテーブルについては、テーブルが作成されたことを確認するフィードバックを受け取ります。
OutputCREATE TABLE
このテーブルにもいくつかのサンプルデータを入力します。
- INSERT INTO dinners (name, birthdate, entree, side, dessert)
- VALUES ('Dolly', '1946-01-19', 'steak', 'salad', 'cake'),
- ('Etta', '1938-01-25', 'chicken', 'fries', 'ice cream'),
- ('Irma', '1941-02-18', 'tofu', 'fries', 'cake'),
- ('Barbara', '1948-12-25', 'tofu', 'salad', 'ice cream'),
- ('Gladys', '1944-05-28', 'steak', 'fries', 'ice cream');
OutputINSERT 0 5
そのコマンドが正常に完了すると、データベースのセットアップは完了です。 次に、SELECT
クエリの基本的なコマンド構造について説明します。
SELECTステートメントを理解する
はじめに述べたように、SQLクエリはほとんどの場合SELECT
ステートメントで始まります。 SELECT
はクエリで使用され、テーブルのどの列を結果セットに返すかを指定します。 クエリには、ほとんどの場合FROM
も含まれます。これは、ステートメントがクエリを実行するテーブルを指定するために使用されます。
通常、SQLクエリは次の構文に従います。
- SELECT column_to_select FROM table_to_select WHERE certain_conditions_apply;
例として、次のステートメントは、dinners
テーブルからname
列全体を返します。
- SELECT name FROM dinners;
Output name
---------
Dolly
Etta
Irma
Barbara
Gladys
(5 rows)
次のように、名前をコンマで区切ることにより、同じテーブルから複数の列を選択できます。
- SELECT name, birthdate FROM dinners;
Output name | birthdate
---------+------------
Dolly | 1946-01-19
Etta | 1938-01-25
Irma | 1941-02-18
Barbara | 1948-12-25
Gladys | 1944-05-28
(5 rows)
特定の列または列のセットに名前を付ける代わりに、SELECT
演算子の後にアスタリスク(*
)を付けることができます。これは、テーブル内のすべての列を表すプレースホルダーとして機能します。 次のコマンドは、tourneys
テーブルからすべての列を返します。
- SELECT * FROM tourneys;
Output name | wins | best | size
---------+------+------+------
Dolly | 7 | 245 | 8.5
Etta | 4 | 283 | 9
Irma | 9 | 266 | 7
Barbara | 2 | 197 | 7.5
Gladys | 13 | 273 | 8
(5 rows)
WHERE
は、指定された条件を満たすレコードをフィルタリングするクエリで使用され、その条件を満たす行は結果から削除されます。 WHERE
句は通常、次の構文に従います。
- . . . WHERE column_name comparison_operator value
WHERE
句の比較演算子は、指定された列を値と比較する方法を定義します。 一般的なSQL比較演算子は次のとおりです。
オペレーター | それが何をするか |
---|---|
= |
平等のテスト |
!= |
不平等のテスト |
< |
未満のテスト |
> |
より大きいテスト |
<= |
以下または等しいかどうかをテストします |
>= |
以上または等しいかどうかをテストします |
BETWEEN |
値が指定された範囲内にあるかどうかをテストします |
IN |
行の値が指定された値のセットに含まれているかどうかをテストします |
EXISTS |
指定された条件で行が存在するかどうかをテストします |
LIKE |
値が指定された文字列と一致するかどうかをテストします |
IS NULL |
NULL 値のテスト |
IS NOT NULL |
NULL 以外のすべての値をテストします |
たとえば、Irmaの靴のサイズを検索する場合は、次のクエリを使用できます。
- SELECT size FROM tourneys WHERE name = 'Irma';
Output size
------
7
(1 row)
SQLではワイルドカード文字を使用できます。これらはWHERE
句で使用する場合に特に便利です。 パーセント記号(%
)は0個以上の不明な文字を表し、アンダースコア(_
)は単一の不明な文字を表します。 これらは、テーブル内の特定のエントリを検索しようとしているが、そのエントリが正確に何であるかがわからない場合に役立ちます。 説明のために、数人の友人のお気に入りのメインディッシュを忘れたが、この特定のメインディッシュは「t」で始まると確信しているとしましょう。 次のクエリを実行すると、その名前を見つけることができます。
- SELECT entree FROM dinners WHERE entree LIKE 't%';
Output entree
-------
tofu
tofu
(2 rows)
上記の出力に基づいて、忘れたメインディッシュはtofu
であることがわかります。
比較的長い名前や読みにくい名前の列またはテーブルがあるデータベースを使用している場合があります。 このような場合、AS
キーワードを使用してエイリアスを作成することにより、これらの名前を読みやすくすることができます。 AS
で作成されたエイリアスは一時的なものであり、作成されたクエリの期間中のみ存在します。
- SELECT name AS n, birthdate AS b, dessert AS d FROM dinners;
Output n | b | d
---------+------------+-----------
Dolly | 1946-01-19 | cake
Etta | 1938-01-25 | ice cream
Irma | 1941-02-18 | cake
Barbara | 1948-12-25 | ice cream
Gladys | 1944-05-28 | ice cream
(5 rows)
ここでは、name
列をn
として、birthdate
列をb
として、dessert
列を次のように表示するようにSQLに指示しました。 d
。
これまでに行った例には、SQLクエリでより頻繁に使用されるキーワードと句が含まれています。 これらは基本的なクエリには役立ちますが、計算を実行したり、スカラー値(複数の異なる値のセットではなく単一の値)を導出しようとしている場合は役に立ちません。あなたのデータ。 ここで、集計関数が機能します。
集計関数
多くの場合、データを操作するとき、必ずしもデータ自体を見たいとは限りません。 むしろ、データに関する情報が必要です。 SQL構文には、SELECT
クエリを発行するだけで、データの計算を解釈または実行できるようにする多数の関数が含まれています。 これらは集約関数として知られています。
COUNT
関数は、特定の基準に一致する行数をカウントして返します。 たとえば、誕生日のメインディッシュに豆腐を好む友達の数を知りたい場合は、次のクエリを発行できます。
- SELECT COUNT(entree) FROM dinners WHERE entree = 'tofu';
Output count
-------
2
(1 row)
AVG
関数は、列の平均(平均)値を返します。 サンプルテーブルを使用すると、次のクエリで友達の平均最高スコアを見つけることができます。
- SELECT AVG(best) FROM tourneys;
Output avg
-------
252.8
(1 row)
SUM
は、特定の列の合計を見つけるために使用されます。 たとえば、あなたとあなたの友人が何年にもわたってボウリングしたゲームの数を確認したい場合は、次のクエリを実行できます。
- SELECT SUM(wins) FROM tourneys;
Output sum
-----
35
(1 row)
AVG
およびSUM
関数は、数値データで使用した場合にのみ正しく機能することに注意してください。 数値以外のデータでそれらを使用しようとすると、使用しているRDBMSに応じて、エラーまたは0
のみが発生します。
- SELECT SUM(entree) FROM dinners;
OutputERROR: function sum(character varying) does not exist
LINE 1: select sum(entree) from dinners;
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
MIN
は、指定された列内の最小値を見つけるために使用されます。 このクエリを使用して、これまでの全体的なボウリングの最悪の記録を確認できます(勝利数の観点から)。
- SELECT MIN(wins) FROM tourneys;
Output min
-----
2
(1 row)
同様に、MAX
は、特定の列で最大の数値を見つけるために使用されます。 次のクエリは、全体として最高のボウリング記録を示しています。
- SELECT MAX(wins) FROM tourneys;
Output max
-----
13
(1 row)
SUM
およびAVG
とは異なり、MIN
およびMAX
関数は、数値データ型とアルファベットデータ型の両方に使用できます。 文字列値を含む列で実行すると、MIN
関数は最初の値をアルファベット順に表示します。
- SELECT MIN(name) FROM dinners;
Output min
---------
Barbara
(1 row)
同様に、文字列値を含む列で実行すると、MAX
関数は最後の値をアルファベット順に表示します。
- SELECT MAX(name) FROM dinners;
Output max
------
Irma
(1 row)
集計関数には、このセクションで説明した以外にも多くの用途があります。 これらは、GROUP BY
句と一緒に使用すると特に便利です。この句については、結果セットの並べ替え方法に影響を与える他のいくつかのクエリ句とともに次のセクションで説明します。
クエリ出力の操作
FROM
およびWHERE
句に加えて、SELECT
クエリの結果を操作するために使用される他のいくつかの句があります。 このセクションでは、より一般的に使用されるいくつかのクエリ句の例を説明し、提供します。
FROM
とWHERE
を除いて、最も頻繁に使用されるクエリ句の1つは、GROUP BY
句です。 これは通常、ある列で集計関数を実行しているときに使用されますが、別の列の値の一致に関連しています。
たとえば、作成した3つのメインディッシュのそれぞれを好む友人の数を知りたいとします。 この情報は、次のクエリで見つけることができます。
- SELECT COUNT(name), entree FROM dinners GROUP BY entree;
Output count | entree
-------+---------
1 | chicken
2 | steak
2 | tofu
(3 rows)
ORDER BY
句は、クエリ結果を並べ替えるために使用されます。 デフォルトでは、数値は昇順で並べ替えられ、テキスト値はアルファベット順に並べ替えられます。 説明のために、次のクエリはname
列とbirthdate
列を一覧表示しますが、結果を誕生日で並べ替えます。
- SELECT name, birthdate FROM dinners ORDER BY birthdate;
Output name | birthdate
---------+------------
Etta | 1938-01-25
Irma | 1941-02-18
Gladys | 1944-05-28
Dolly | 1946-01-19
Barbara | 1948-12-25
(5 rows)
ORDER BY
のデフォルトの動作は、結果セットを昇順でソートすることであることに注意してください。 これを逆にして結果セットを降順でソートするには、DESC
でクエリを閉じます。
- SELECT name, birthdate FROM dinners ORDER BY birthdate DESC;
Output name | birthdate
---------+------------
Barbara | 1948-12-25
Dolly | 1946-01-19
Gladys | 1944-05-28
Irma | 1941-02-18
Etta | 1938-01-25
(5 rows)
前述のように、WHERE
句は、特定の条件に基づいて結果をフィルタリングするために使用されます。 ただし、集計関数でWHERE
句を使用すると、エラーが返されます。これは、少なくとも3人の友達のお気に入りの側を見つけるための次の試みの場合と同様です。
- SELECT COUNT(name), side FROM dinners WHERE COUNT(name) >= 3;
OutputERROR: aggregate functions are not allowed in WHERE
LINE 1: SELECT COUNT(name), side FROM dinners WHERE COUNT(name) >= 3...
HAVING
句がSQLに追加され、WHERE
句と同様の機能を提供すると同時に、集計関数とも互換性があります。 WHERE
は個々のレコードに適用され、HAVING
はグループレコードに適用されるという点で、これら2つの句の違いを考えると役立ちます。 このため、HAVING
句を発行するときは常に、GROUP BY
句も存在する必要があります。
次の例は、少なくとも3人の友人のお気に入りのおかずを見つけるための別の試みですが、これはエラーなしで結果を返します。
- SELECT COUNT(name), side FROM dinners GROUP BY side HAVING COUNT(name) >= 3;
Output count | side
-------+-------
3 | fries
(1 row)
集計関数は、特定のテーブルの特定の列の結果を要約するのに役立ちます。 ただし、複数のテーブルの内容をクエリする必要がある場合が多くあります。 次のセクションでは、これを行うためのいくつかの方法について説明します。
複数のテーブルのクエリ
多くの場合、データベースには複数のテーブルが含まれ、それぞれが異なるデータセットを保持しています。 SQLは、複数のテーブルに対して単一のクエリを実行するためのいくつかの異なる方法を提供します。
JOIN
句を使用して、クエリ結果の2つ以上のテーブルの行を組み合わせることができます。 これは、テーブル間の関連する列を見つけることによってこれを行い、出力で結果を適切にソートします。
SELECT
ステートメントは、通常、次の構文に従います。
- SELECT table1.column1, table2.column2
- FROM table1
- JOIN table2 ON table1.related_column=table2.related_column;
JOIN
句は複数のテーブルの内容を比較するため、前の例では、列の名前の前にテーブルの名前とピリオドを付けて、各列を選択するテーブルを指定していることに注意してください。 前のセクションで行ったように、単一のテーブルから選択する場合は必要ありませんが、どのクエリに対してもこのように列を選択するテーブルを指定できます。 サンプルデータを使用して例を見ていきましょう。
友達の一人一人に誕生日プレゼントとしてボウリングシューズを買いたいと想像してみてください。 友達の生年月日と靴のサイズに関する情報は別々のテーブルに保持されているため、両方のテーブルを別々にクエリして、それぞれの結果を比較できます。 ただし、JOIN
句を使用すると、1回のクエリで必要なすべての情報を見つけることができます。
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- JOIN dinners ON tourneys.name=dinners.name;
Output name | size | birthdate
---------+------+------------
Dolly | 8.5 | 1946-01-19
Etta | 9 | 1938-01-25
Irma | 7 | 1941-02-18
Barbara | 7.5 | 1948-12-25
Gladys | 8 | 1944-05-28
(5 rows)
この例で使用されているJOIN
句は、他の引数なしで、 inner JOIN
句です。 これは、両方のテーブルで値が一致するすべてのレコードを選択して結果セットに出力し、一致しないレコードは除外されることを意味します。 このアイデアを説明するために、他のテーブルに対応するエントリがない新しい行を各テーブルに追加しましょう。
- INSERT INTO tourneys (name, wins, best, size)
- VALUES ('Bettye', '0', '193', '9');
- INSERT INTO dinners (name, birthdate, entree, side, dessert)
- VALUES ('Lesley', '1946-05-02', 'steak', 'salad', 'ice cream');
次に、前のSELECT
ステートメントをJOIN
句を使用して再実行します。
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- JOIN dinners ON tourneys.name=dinners.name;
Output name | size | birthdate
---------+------+------------
Dolly | 8.5 | 1946-01-19
Etta | 9 | 1938-01-25
Irma | 7 | 1941-02-18
Barbara | 7.5 | 1948-12-25
Gladys | 8 | 1944-05-28
(5 rows)
tourneys
テーブルにはLesleyのエントリがなく、dinners
テーブルにはBettyeのエントリがないため、これらのレコードはこの出力に含まれていないことに注意してください。
ただし、 external JOIN
句を使用して、テーブルの1つからすべてのレコードを返すことは可能です。 外側のJOIN
句は、LEFT JOIN
、RIGHT JOIN
、またはFULL JOIN
のいずれかとして記述されます。
LEFT JOIN
句は、「左側」のテーブルからすべてのレコードを返し、右側のテーブルから一致するレコードのみを返します。 外部結合のコンテキストでは、左側のテーブルはFROM
句によって参照されるテーブルであり、右側のテーブルはJOIN
ステートメントの後に参照される他のテーブルです。
前のクエリを再度実行しますが、今回はLEFT JOIN
句を使用します。
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- LEFT JOIN dinners ON tourneys.name=dinners.name;
このコマンドは、右側のテーブルに対応するレコードがない場合でも、左側のテーブル(この場合はtourneys
)からすべてのレコードを返します。 右側のテーブルに一致するレコードがない場合は常に、RDBMSに応じて、空白の値またはNULL
として返されます。
Output name | size | birthdate
---------+------+------------
Dolly | 8.5 | 1946-01-19
Etta | 9 | 1938-01-25
Irma | 7 | 1941-02-18
Barbara | 7.5 | 1948-12-25
Gladys | 8 | 1944-05-28
Bettye | 9 |
(6 rows)
ここで、今度はRIGHT JOIN
句を使用して、クエリを再度実行します。
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- RIGHT JOIN dinners ON tourneys.name=dinners.name;
これにより、右側のテーブル(dinners
)からすべてのレコードが返されます。 レスリーの生年月日は右側のテーブルに記録されていますが、左側のテーブルには対応する行がないため、name
列とsize
列はその行に空白の値として返されます。
Output name | size | birthdate
---------+------+------------
Dolly | 8.5 | 1946-01-19
Etta | 9 | 1938-01-25
Irma | 7 | 1941-02-18
Barbara | 7.5 | 1948-12-25
Gladys | 8 | 1944-05-28
| | 1946-05-02
(6 rows)
句のOUTER
の部分が暗示されていますが、左結合と右結合はLEFT OUTER JOIN
またはRIGHT OUTER JOIN
と記述できることに注意してください。 同様に、INNER JOIN
を指定すると、JOIN
を書き込んだ場合と同じ結果が得られます。
FULL JOIN
と呼ばれる4番目の結合句があり、PostgreSQLを含む一部のRDBMSディストリビューションで使用できます。 FULL JOIN
は、null値を含む、各テーブルのすべてのレコードを返します。
- SELECT tourneys.name, tourneys.size, dinners.birthdate
- FROM tourneys
- FULL JOIN dinners ON tourneys.name=dinners.name;
Output name | size | birthdate
---------+------+------------
Dolly | 8.5 | 1946-01-19
Etta | 9 | 1938-01-25
Irma | 7 | 1941-02-18
Barbara | 7.5 | 1948-12-25
Gladys | 8 | 1944-05-28
Bettye | 9 |
| | 1946-05-02
(7 rows)
注:この記事の執筆時点では、FULL JOIN
句はMySQLまたはMariaDBのいずれでもサポートされていません。
FULL JOIN
を使用して複数のテーブルのすべてのレコードをクエリする代わりに、UNION
句を使用できます。
UNION
演算子は、JOIN
句とは少し異なる動作をします。単一のSELECT
ステートメントを使用して複数のテーブルからの結果を一意の列として出力する代わりにUNION
は2つのSELECT
ステートメントの結果を1つの列にまとめます。
説明のために、次のクエリを実行します。
- SELECT name FROM tourneys UNION SELECT name FROM dinners;
このクエリは、重複するエントリを削除します。これは、UNION
演算子のデフォルトの動作です。
Output name
---------
Irma
Etta
Bettye
Gladys
Barbara
Lesley
Dolly
(7 rows)
すべてのエントリ(重複を含む)を返すには、UNION ALL
演算子を使用します。
- SELECT name FROM tourneys UNION ALL SELECT name FROM dinners;
Output name
---------
Dolly
Etta
Irma
Barbara
Gladys
Bettye
Dolly
Etta
Irma
Barbara
Gladys
Lesley
(12 rows)
結果テーブルの列の名前と数は、最初のSELECT
ステートメントによって照会された列の名前と数を反映しています。 UNION
を使用して複数のテーブルから複数の列をクエリする場合、各SELECT
ステートメントは同じ数の列をクエリする必要があり、それぞれの列は同様のデータ型である必要があり、それぞれの列は類似している必要があります。 SELECT
ステートメントは同じ順序である必要があります。 次の例は、異なる数の列をクエリする2つのSELECT
ステートメントでUNION
句を使用するとどうなるかを示しています。
- SELECT name FROM dinners UNION SELECT name, wins FROM tourneys;
OutputERROR: each UNION query must have the same number of columns
LINE 1: SELECT name FROM dinners UNION SELECT name, wins FROM tourne...
複数のテーブルをクエリする別の方法は、サブクエリを使用することです。 サブクエリ(内部またはネストされたクエリとも呼ばれます)は、別のクエリに囲まれたクエリです。 これらは、クエリの結果を別の集計関数の結果に対してフィルタリングしようとしている場合に役立ちます。
このアイデアを説明するために、バーバラよりも多くの試合に勝った友達を知りたいとします。 バーバラが勝った試合の数をクエリしてから別のクエリを実行して、それより多くのゲームに勝った人を確認するのではなく、1つのクエリで両方を計算できます。
- SELECT name, wins FROM tourneys
- WHERE wins > (
- SELECT wins FROM tourneys WHERE name = 'Barbara'
- );
Output name | wins
--------+------
Dolly | 7
Etta | 4
Irma | 9
Gladys | 13
(4 rows)
このステートメントのサブクエリは1回だけ実行されました。 name
列のBarbara
と同じ行のwins
列から値を見つけるだけでよく、サブクエリと外部クエリによって返されるデータは独立しています。お互いに。 ただし、目的のデータを返すために、外部クエリが最初にテーブル内のすべての行を読み取り、それらの値をサブクエリによって返されたデータと比較する必要がある場合があります。 この場合、サブクエリは相関サブクエリと呼ばれます。
次のステートメントは、相関サブクエリの例です。 このクエリは、同じ靴のサイズの友達の平均よりも多くのゲームに勝った友達を見つけようとします。
- SELECT name, size FROM tourneys AS t
- WHERE wins > (
- SELECT AVG(wins) FROM tourneys WHERE size = t.size
- );
クエリを完了するには、最初に外部クエリからname
列とsize
列を収集する必要があります。 次に、その結果セットの各行を内部クエリの結果と比較します。これにより、同じ靴のサイズを持つ個人の平均勝利数が決定されます。 同じ靴のサイズの友達が2人しかいないため、結果セットには1つの行しかありません。
Output name | size
------+------
Etta | 9
(1 row)
前述のように、サブクエリを使用して、複数のテーブルからの結果をクエリできます。 最後の例でこれを説明するために、グループの史上最高のボウラーのためにサプライズディナーを投げたいとしましょう。 次のクエリを使用して、ボウリングの記録が最も優れている友達を見つけて、お気に入りの食事を返すことができます。
- SELECT name, entree, side, dessert
- FROM dinners
- WHERE name = (SELECT name FROM tourneys
- WHERE wins = (SELECT MAX(wins) FROM tourneys));
Output name | entree | side | dessert
--------+--------+-------+-----------
Gladys | steak | fries | ice cream
(1 row)
このステートメントにはサブクエリが含まれているだけでなく、そのサブクエリ内にサブクエリも含まれていることに注意してください。
結論
クエリの発行は、データベース管理の領域で最も一般的に実行されるタスクの1つです。 phpMyAdminやpgAdminなど、クエリを実行して結果を視覚化できるデータベース管理ツールがいくつかありますが、コマンドからSELECT
ステートメントを発行します。 lineは今でも広く実践されているワークフローであり、より優れた制御を提供することもできます。
SQLを初めて使用する場合は、 SQLチートシートを参照として使用し、公式のPostgreSQLドキュメントを確認することをお勧めします。 さらに、SQLおよびリレーショナルデータベースについて詳しく知りたい場合は、次のチュートリアルが役立つ場合があります。