SELECT クエリ
SELECT クエリは、記録されたテーブルデータを閲覧するためのコマンドです。SQL の基本となる SQL 文のひとつです。SQL データ文とも呼ばれます。
テーブルには表計算のように行列の概念があり、SELECT クエリは指定された行を検索し出力します。
SELECT * FROM table_name;
この例は table_name というテーブルに記録されている全データを行列で返します。
クエリとは、問い合わせ
を意味し、データベースではデータの検索( SELECT )、入力( INSERT )、更新( UPDATE )、削除( DELETE )といった命令をサーバーに送る行為を指します。
クエリには、作成( CREATE )、変更( ALTER )、削除( DROP )といった SQL スキーマ文も含みます。
構文(Syntax)
SELECT 文はデータベースに記録されたデータを取得することができる SQL 文です。リテラル値や関数による結果を取得することもできます。
SELECT * FROM table_name;
WHERE といった条件によってデータを抽出することができます。
MySQL
SELECT 文は MySQL では以下のような仕様になっています。
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr] ...
[into_option]
[FROM table_references
[PARTITION partition_list]]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
[HAVING where_condition]
[WINDOW window_name AS (window_spec)
[, window_name AS (window_spec)] ...]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[into_option]
[FOR {UPDATE | SHARE}
[OF tbl_name [, tbl_name] ...]
[NOWAIT | SKIP LOCKED]
| LOCK IN SHARE MODE]
[into_option]
into_option: {
INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name] ...
}
PostgreSQL
PostgreSQL では以下のうような仕様になっています。
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] * | expression [ [ AS ] output_name ] [, ...] [ FROM from_item [, ...] ] [ WHERE condition ] [ GROUP BY expression [, ...] ] [ HAVING condition [, ...] ] [ WINDOW window_name AS ( window_definition ) [, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ] [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ] [ LIMIT { count | ALL } ] [ OFFSET start [ ROW | ROWS ] ] [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ] [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT ] [...] ]
句について
SELECT 文はいくつかの句で構成されています。例えば以下のような句があります。
句
はデータベースによって節
、文節
とも呼ばれます。Oracle では節
、MySQLやPostgreSQL では句
と呼ばれることが多いようです。
このサイトでは句
と呼ぶようにしています。
SELECT 句
一番簡単な SELECT 文は、以下のようなテーブルの全データを取得します。*
がすべてのカラムを対象にするという指定です。
SELECT * FROM table_name;
上記の例では FROM 句もあります。FROM 句の対象はテーブルです。
FROM がある場合には、FROM に指定されたテーブルの全てのデータを対象にするという前提になります。
カラムを指定するには,
で区切ってそのカラム名を並べます。結果が指定されたカラムの列データになります。
SELECT id, name FROM table_name;
FROM 句はない場合もあります。例えば以下のような組み込み関数
を参照する場合には FROM 句は必ずしも必要ではありません。
SELECT now();
SELECT の直後はカラム名の指定だけではなく計算式、数値や文字列といったリテラル値が指定できます。
mysql> SELECT user, host, date( password_last_changed ), 'test' FROM mysql.user; +------------------+-----------+-------------------------------+------+ | user | host | date( password_last_changed ) | test | +------------------+-----------+-------------------------------+------+ | debian-sys-maint | localhost | 2023-06-12 | test | | mysql.infoschema | localhost | 2023-06-12 | test | | mysql.session | localhost | 2023-06-12 | test | ...
date( password_last_changed ) は password_last_changed から日付だけを取り出します。'test' は文字列、リテラル値です。
カラム名は AS 句によって変更することができます。
mysql> SELECT user, host, date( password_last_changed ) AS password_changed_date, 'test' AS 'test_literal' FROM mysql.user; +------------------+-----------+-----------------------+--------------+ | user | host | password_changed_date | test_literal | +------------------+-----------+-----------------------+--------------+ | debian-sys-maint | localhost | 2023-06-12 | test | | mysql.infoschema | localhost | 2023-06-12 | test | | mysql.session | localhost | 2023-06-12 | test | ...
FROM 句
FROM には1つのテーブルの他に一時テーブル、ビュー、結合されたテーブルも指定できます。FROM に指定できるのは行列(テーブル)で表されたデータ群が指定できます。
一時テーブル
一時テーブルにはサブクエリによって取得した行列データがあります。
SELECT t.id FROM ( SELECT id, name FROM table_name ) AS t;
上記の例はあまり意味がありませんが、以下のテーブルの結合でこのような書き方を使用します。
テーブルビュー
テーブルビューは予めテーブルデータの取得方法を定義しておくものです。
CREATE VIEW table_name_view AS SELECT * FROM table_name;
ビューもテーブルと同じように FROM で指定できます。
SELECT * FROM table_name_view;
ビューは以下のテーブルを結合した状態を予め定義しておくことができます。
テーブルの結合
テーブルの結合は複数のテーブルを1つのテーブルとして定義できるものです。以下は内部結合と呼ばれ複数のテーブルで一致する部分だけが取得できます。
SELECT * FROM table_name INNER JOIN join_table AS j ON table_name.id = j.table_id ;
テーブルの結合を定義した SQL 文を毎度編集するのは大変です。ビューを作成することによってそのビューを参照するだけで結合されたテーブルを取得することができます。
CREATE VIEW table_name_view AS SELECT * FROM table_name INNER JOIN join_table AS j ON table_name.id = j.table_id ;
テーブルの結合はサブクエリー(副問合せ)
でも使用されます。
WHERE 句
条件を指定した行データの抽出をする場合は WHERE 句を加えます。
この WHERE 句によってテーブルデータから条件にあった行のみが対象になります。
SELECT * FROM table_name WHERE id <= 100;
上記の例は id が 100 以下のレコードを検索して取得します。
詳しくはWHERE 句
ページを参照してください。
GROUP BY 句
GROUP BY 句は重複するカラムのデータを対象にして行をグループ化します。集計などに使用されます。
SELECT name, COUNT(*) FROM table_name GROUP BY name;
注意点として取得するカラムにグループ化できないものを含むことができません。
例えば、併せてレコードid
を取得するしようとするとグループ化によって対象にできないカラムがある
というエラーが返されます。
> SELECT id, goods_id FROM sales_slip GROUP BY goods_id;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.sales_slip.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
また、GROUP BY 句によってグループごとに分けられた行の検索には HAVING 句を使用します。
詳しくはGROUP BY 句
ページを参照してください。
HAVING 句
HAVING 句は GROUP BY 句で使用する条件による抽出(フィルタリング)のために使用します。
WHERE による条件は FROM で指定されたテーブルに機能し、GROUP BY で集約されるデータには機能しません。
GROUP BY による集約されるデータに抽出条件が機能するようにするには HAVING 句を利用します。
SELECT *, count(*) FROM table_name GROUP BY id HAVING count(*) > 2;
上記の例では、カラムに集約関数、count() を追加し、HAVING 句で同じ id をもつ行が2より大きい場合を抽出します。
ORDER BY 句
ORDER BY 句は並べ替えを行います。カラムのデータによって昇順、降順で並べ替えができます。
ORDER BY 句で並びを指定しない限りは、クエリによる結果セットの並びは決まっていません。ORDER BY 句を使用することでデータは明確に並び替えをすることができます。
SELECT * FROM table_name ORDER BY id,name;
ORDER BY 句はデフォルトで昇順で並び替えが行われます。DESC を指定することで降順に指定することができます。
LIMIT 句
LIMIT 句は、検索されたレコードから指定された数の行を返します。
SELECT * FROM table_name LIMIT 100;
上記の例では、検索された順で 100 行までを返してきます。レコードが 100 行に満たない場合は検索されたすべての行を返してきます。
取得する行数の開始位置は OFFSET 句で指定します。例えば、101 行目から 100 行分を取得するには以下のようにします。
SELECT * FROM table_name LIMIT 100 OFFSET 100;
返されたるレコードは、ORDER BY 句によってレコードを並べないと常に順番が安定しないかもしれません。LIMIT 句を利用する場合は ORDER BY 句を使用した方がよいでしょう。
SELECT * FROM table_name LIMIT 100 OFFSET 100 ORDER BY id;
CASE 句
CASE 句を使用することで条件分岐を加えることができます。
SELECT id, CASE table_name.gender WHEN gender = 'M' THEN 'Mr.' WHEN gender = 'F' THEN 'Ms.' END; FROM table_name;
上記のクエリを実行すると、gender が 'M' では 'Mr.' を、 gender = 'F' では 'Ms.' を返します。
テーブル結合
テーブルの結合は JOIN 句や INNER JOIN 句を使用して複数のテーブルを組み合わせます。
JOIN 句に ON を付加することで任意の行のみを抽出します。
SELECT * FROM goods AS g JOIN sales_slip AS s ON g.id = s.goods_id;
テーブルの結合には外部結合と内部結合があります。JOIN 句はデフォルトの設定では内部結合です。
JOIN 句の代わりに INNER JOIN 句によって明確に内部結合であることを指定することもできます。
テーブル結合について詳しくはテーブルの結合 JOIN
を参照してください。
その他
DISTINCT 句 重複データを整理
重複したデータを整理した形でデータ返させるには DISTINCT 句を使用します。
DISTINCT 句は重複するデータを整理したいカラム名の直前に編集します。
SELECT DISTINCT user_id FROM account;
DISTINCT 句とは別に ALL 句があります。ALL はデフォルトでの指定と同じになります。
日時要素のみを取得
日付・時刻データから年度や月度、日付のみを取り出すには EXTRACT() 関数を使用します。
> SELECT EXTRACT( YEAR FROM date_time ) AS year, EXTRACT( MONTH FROM date_time ) AS month FROM sales_slip; +------+-------+ | year | month | +------+-------+ | 2023 | 10 | | 2023 | 9 | | 2023 | 9 | | 2023 | 9 | | 2023 | 9 | +------+-------+
EXTRACT()
は日時要素を取得するための関数です。EXTRACT( 日時要素 FROM 日時データ )
といった使い方をします。
年度は YEAR、月度は MONTH、日にちは DAY です。時間は HOUR、分は MINUTE、秒は SECOND です。
