SQLをはじめよう - 初心者でもわかる、構文とデータ取得の基本

リレーショナルデータベース管理システム(RDBMS)において、データの操作や定義を行うためのデータベース言語であるSQL。“データ”の重要性が謳われるようになった昨今において、この言語はより重要性を増しています。本稿では日本MySQLユーザ会の副代表であり、データベースを中心とした業務システムの設計・コンサルティングを手掛ける坂井恵さんが、「SQLを学びはじめたばかりの若手IT技術者」や「社内のデータを利用したい非IT技術者」に向けて、SQLによるデータ操作の基礎を解説します。

SQLをはじめよう - 初心者でもわかる、構文とデータ取得の基本

企業活動において、近年ますます、蓄積されたデータの活用が重要になっています。自社の持つ大量のデータの中から必要なデータを抽出・集計するという操作は、以前はITエンジニアが用意した画面を通して限定的にのみ行うことができるのが一般的でした。

しかし最近は、ITエンジニアではないビジネス担当者も、クエリ(SQLで書いた命令のこと)を自分で書いて、データの取得や集計をするケースも増えてきています。担当者が自らクエリを書くことには2つのメリットがあります。

  • スピード感

    • 今まで他の人(ITエンジニア)に依頼をして実施していたものを、思いついたらすぐに実施できる
  • きめ細かな抽出や集計

    • 業務を知る担当者が自ら抽出・集計操作を行うことで、より目的に合致したデータを取得できる

SQLは、使いこなそうとすると非常に奥深く、習得には時間がかかります。しかし、「とりあえず」シンプルな抽出を行うだけなら、実はものすごくとっつきやすい言語なのです。さぁ、怖がらずにSQLの世界へと足を踏み入れてみましょう。

本稿では、データが保存されている形式(テーブル)と、そこから抽出する言語(SQL)といった、初歩的な理解を得ることを目指します。

データベースとSQL

「データベース」と言っても色々な仕組みのものがあります。本稿ではその中でも広く使われている「リレーショナルデータベース管理システム(以下、RDBMS)」を用いたデータの取り扱いについて解説します。

RDBMSはデータベース内の「テーブル」に入っているデータを「SQL」という言語を使って操作します。SQLを使って、主に以下のようなデータ操作が可能です。

操作名 機能
追加(新規登録) テーブルにデータを1件追加する
更新 テーブル上に既に存在するデータの一部を書き換える
削除 テーブル上に既に存在するデータ行を削除する
検索 テーブル上に存在するデータを、条件を指定して抽出する

一般的に、最初の3つが更新系、最後の1つが参照系と呼ばれています。本記事の対象読者がいきなり更新系のSQL(追加、更新、削除)を使ってテーブルデータの変更を行うケースは、あまりないと思いますので、本稿では検索のSQLをピックアップして説明します。

まずは「テーブル」の概要をサクッと学ぶ

SQLを使って操作するRDBMSでは、「テーブル」と呼ばれる形式でデータを保管しています。本当は細かい部分で全然違うのですが、とりあえずのイメージとしては Excelなどのワークシートの「表(ひょう)」をイメージすればよいでしょう。行と列からなるマトリックスです。

ただし、Excelの場合は、データの入ったファイルをコピーしたり移動したりできますが、RDBMSではデータはサーバ上の一か所に置かれ、SQLを使ってのみデータ操作が可能です。

テーブルの特徴は以下のとおりです。

  • 1行が1件のデータを表す。
  • 列ごとに決められた意味(「郵便番号」や「氏名」「人口」など)を持つ。
  • 列には「型」が決められている。型とは大まかに「数値」「文字列」「日付」のようなもの(本当はもう少し細分化されています)。決められた型以外の値をその列に格納することはできない(数値型の列に「不明」のような文字列を入れることはできない)
  • 各行は、格納されている状態では順序の概念はなく、順序不定である。つまり「4行目のデータ」といった表現で行を特定することはできない。

特徴をまとめると、以下の図1の表のようなイメージになります。

1

SQLの基本構文はたった4つの言葉を知っておけばOK

テーブルからデータを抽出するには、SQLのひとつである SELECT文を使います。SELECT文のもっとも基本的な構文は図2のようになっています。

2

構文を簡単に説明しましょう。SELECTの後ろの枠内には、取得したい列名を羅列します。FROMの枠には取得元のテーブル名。WHEREの後ろには抽出したい行に関する条件を指定し、ORDER BY の後ろに指定した順序に並べてデータを取得します。また、SQLの命令は; (セミコロン)で終わります。
基本的に、上記の4つの枠を穴埋めするだけで、テーブルからのデータ抽出ができてしまうのです。簡単でしょう?

データの地図となる、テーブルレイアウトを読んでみよう

テーブルからデータ抽出を行うには、対象とするテーブルのレイアウトを知っている必要があります。これは通常、データベースを管理するチームから、テーブルレイアウトまたはテーブル定義書といった名前の情報をもらえるはずです。概ね図3のような情報が掲載されているかと思います。特に見るべきところは、テーブル名と列名の部分です。

3

ここでは、このテーブルに図4のようなデータが入っているものとして、説明を続けます。

まずはここから!「SELECT」と「FROM」の使い方を知ろう

さっそく、先ほどの穴埋めをする形でSQLを書いてみましょう。SQLを書くときには、まず「どのテーブルからデータを取るか」を決める必要があります。テーブル定義書を見ると今回は URIAGE_DAILY というテーブル名だとわかります。FROMの後ろに書き入れましょう。

次に、そのテーブルから、どの列の値を取ってきたいのかを、SELECT の後ろに書き入れます。ここでは例として、ID URI_DATE ITEM_CODE TOTAL_AMOUNT の4つの列を取ってくることにしましょう。

列名の指定は、コンマで区切って羅列します。また、コンマの前後には空白を入れても入れなくても構いません。なお、著者のお勧めスタイルは、「コンマの前には空白を入れず、コンマの後ろに空白を入れる」です。また、空白を入れることが可能な場所では、改行を入れても構いません。

SELECT ID, URI_DATE, ITEM_CODE, TOTAL_AMOUNT
  FROM URIAGE_DAILY;

これだけで、URIAGE_DAILYテーブルの指定した列の値を取ってくるクエリになります。「どの行を抽出したいのか」の条件を指定していないので、テーブルにある全件のデータが得られます。抽出後のデータは以下の図5のようなイメージで出力されます。

4

列の指定は、必ずしもテーブル定義の順でなくても構いません。IDの次に真っ先にTOTAL_AMOUNTを得たいのであれば、

SELECT ID, TOTAL_AMOUNT, URI_DATE, ITEM_CODE
  FROM URIAGE_DAILY;

のようにすれば、以下図6のように指定した列の順で結果を得ることができます。

5

演算子と関数を活用して列の値を加工してみよう

取得する列の値は、データベースにある値をそのまま取ってくる以外にも、ちょっとした演算加工を行うこともできます。ここでは、数字の計算の例と文字列の加工の例を紹介します。

まず数値の演算の例です。あまり業務としては現実的な例ではないのですが「もし仮に各日の売り上げ個数が倍あったら?」といったシナリオで、データを抽出してみます

SELECT ID, URI_DATE, ITEM_CODE, NOF*2 AS NOF_TWICE, TOTAL_AMOUNT*2 AS TOTAL_TWICE
  FROM URIAGE_DAILY;

NOF*2TOTAL_AMOUNT*2 の部分が「2倍する」の計算式です。計算した結果の列(これは元の列とは異なります)に名前をつけるために AS NOF_TWICE として、ASを使って列名をつけてあげています(AS を省略し、NOF*2 NOF_TWICE のようにして別名をつけるDBMSもあります)。この場合、以下の図7のような結果が得られるでしょう。

6

*はかけ算の演算子で、+ - * / といった四則演算が使用可能です。また、今回はNOF*2とスペースを空けずに記述しましたが、NOF * 2 NOF* 2 などスペースを空けても同様の結果が得られます。自分や周りの人が見やすい方法で書くと良いでしょう。

続いて文字列演算、つまり文字列の加工例を紹介します。文字列の加工には「関数」と呼ばれる機能を利用します。関数とは、元の値に対してさまざまな加工処理を行うしくみです。文字列に対してその一部を取り出したり、文字列の長さを得たり、数字に対しては、平方根を得たり、三角関数の結果を得たりなど、たくさんの関数がRDBMSには用意されています。

ここではITEM_TYPE_NAMEが長すぎるので、先頭4文字だけを採用する例を以下に示します。

SELECT ID, URI_DATE, SUBSTRING(ITEM_TYPE_NAME, 1, 4) AS ITEM_TYPE_NAME_4, ITEM_CODE, TOTAL_AMOUNT
  FROM URIAGE_DAILY;

SUBSTRING() が、文字列を加工する関数の例です。SUBSTRING()関数を使って、ITEM_TYPE_NAMEの1文字目から4文字目を加工して取得し、その結果に ITEM_TYPE_NAME_4 という新しい列名をつけています。これも結果を見てみましょう。

7

使用できる関数や演算子は、RDMBSごとに異なります。あなたがお使いのSQLのマニュアルの中から「関数」に関する章を開いて、どんな関数が使えるかを確認しておきましょう。今回紹介した SUBSTRING() も、RDBMSによって少しずつ異なる場合があります(SUBSTRだったりMIDだったり)。

WHERE句で行をしぼり、必要なデータだけを手に入れる

ここまではFROM句とSELECT句(FROMの後ろの四角枠、SELECTの後ろの四角枠という程度の意味です)を指定することで、指定したテーブルから、欲しいカラムの値やカラムの値を少々加工して取得する方法を覚えました。

次に、欲しい行だけを取得する方法を学びましょう。今回の例ではデータはたったの8件ですが、通常、データベースには、何万件、何百万件のデータが登録されているものです。毎回、全件を取ってくるのでは、サーバから転送(ダウンロード)してくる量も増えてしまうし、ダウンロードしたファイルのサイズも大きくて取り回しがしにくいものになってしまいます。適切に必要なデータ行だけを取得するテクニックを身につけましょう。

行をしぼる条件の書き方

自分が欲しい行に関する条件を WHERE句(★図2★の WHEREの後ろの四角枠)に書きます。条件は

  1. URI_DATEが9月以前のもの
  2. ITEM_CODEが101のもの

で、この場合は「AND」という句を使用します。 「ITEM_CODEが925-25 かまたは ITEM_CODEが925-35のもの」 のように複数のものを指定することもでき、この場合は「OR」を使用します。

さて、ひとつひとつの条件は、「列名 演算子 値」の形式であらわします。といっても、これじゃわかりませんよね。もう少し説明しましょう。「演算子」というのは「=」や「>」などの記号だ、と言えばイメージがわくでしょうか。「ITEM_CODEが101のもの」はITEM_CODE = 101となり、「URI_DATEが9月以前」というのはURI_DATE <= '2019/09/30'となります。

主な演算子には、以下のものがあります。

演算子 意味 読み方
= 一致するもの いこーる
<> 一致しないもの のっといこーる
> 左のほうが大きいもの だいなり
>= 左のほうが大きいか一致するもの / 以上 だいなりいこーる
< 右のほうが大きいもの しょうなり
<= 右のほうが大きいか一致するもの / 以下 しょうなりいこーる
LIKE 文字列の部分一致 らいく

※<>(ノットイコール)は!= という書き方もありますが、前者を用いる方がSQLではより一般的です。

一致や、大小判定はすぐに分かると思いますので、ここでは LIKE についてもう少し紹介しましょう。

LIKEは、文字列の部分一致を指定する演算子です。指定する右辺の値には、文字列のうち「なんでも良い部分」を「%」の記号で表します。例えば、「KIRE ではじまる文字列」を表す場合はKIRE%で、「ン で終わる文字列」は%ンとなります。

では、ここまでの説明を元に

  • 売り上げ日付が9月30日以前
  • 売上数量が10個を越えているもの
  • 上記2条件を満たすID, 売上日付, 商品コード, 数量 を得る

というクエリは以下のようになります。

SELECT ID, URI_DATE, ITEM_CODE, NOF
  FROM URIAGE_DAILY
 WHERE URI_DATE<='2019/09/30'
   AND NOF > 10;

また、「9月30日以前」という条件だけでは過去全てのデータが取得できてしまいますが、実際の現場では「9月のデータが欲しい」というケースも多いでしょう。この場合は、加えて「9月1日以降で、かつ」という条件を指定すれば良いので、SQLは以下のようになります。

SELECT ID, URI_DATE, ITEM_CODE, NOF
  FROM URIAGE_DAILY
 WHERE URI_DATE>='2019/09/01'
   AND URI_DATE<='2019/09/30'
   AND NOF > 10;

もうひとつ。今回のように日付や数値の範囲を表す場合、もう少し正確に言うと、値の下限と上限を含む形での範囲を指定する場合には、BETWEENという特別な書き方もあります。BETWEENを使うと、先ほどのクエリは以下のように書き換えることができます。

SELECT ID, URI_DATE, ITEM_CODE, NOF
  FROM URIAGE_DAILY
 WHERE URI_DATE BETWEEN '2019/09/01' AND '2019/09/30'
   AND NOF > 10;

ORDER BY句を使って抽出したデータを並び替えよう

本稿の前半で「保存されているデータには順序はない」と説明したとおり、順序のない保存データから取り出したデータにも、当然、順序はありません。取り出す度に変化する可能性がある「順不同」だと考えてください。

実際にクエリを流してみると、期待した順序でそれっぽく結果を得られるように見えることもありますが、「たまたま」であることを忘れないでください。この、結果の順序については、「今まで(たまたま)それっぽい並びで得られていたものが、ある日急に、順序が壊れた!」と、初心者の人が勘違いしてしまう最大のポイントのひとつでもあるので、強調しておきます。

結果を得る際の順序を指定するためには、最後に残った四角枠である「ORDER BY」句に、並び替えに使うカラム名を羅列します。たとえば、売上日付順であれば

  ORDER BY URI_DATE

このように表します。特に指定しない場合は昇順(小さい順)で並びます。降順(大きい順)にしたいときには、以下のようにカラム名の後ろに「DESC」と指定します。

  ORDER BY URI_DATE DESC

さらに、同じ日付の中では合計金額の大きい順にしたいときには、

  ORDER BY URI_DATE, TOTAL_MOUNT DESC

となります。

まとめ

まったくSQLを触ったことがない人が、まずデータが格納されている「テーブル」のイメージをつかんで、実際にデータを取得できるまでを目指して説明してきました。

あらためてもう一度、再掲した図2を見てください。

8

ここまでに学んだ内容をまとめると、SQLの基本構文とは

  • どのカラムを(どう加工して): SELECT
  • どのテーブルから:FROM
  • どの行を:WHERE
  • どの順序で:ORDER BY

という、非常にシンプルな命令であることが分かると思います。

SQLを覚えることで、自分自身でデータを取得できるようになるのは素晴らしいことです。業務で、SQLを使って自分でデータを取得できる環境を手に入れたあなた。初めての作業に「面倒くさいなぁ」と思うこともあるかもしれません。でも、業務に精通したあなた自身が、会社の持つ膨大なデータを自分の手で取得できるようになるとき、きっとお仕事の手順がかわり、良い方向へと前進していくことでしょう。

今回紹介したのは、SQLのテクニックの中でも、ほんの入り口の、基本中の基本の話です。SQLは実はもっと複雑なこともできます。そんな魅力についてはまた機会あればお伝えしたいと思います。

坂井 恵 (さかい・けい) 9 @sakaik

10
日本MySQLユーザ会副代表。データベースを中心とした業務システムの設計・コンサルティングを手掛ける有限会社アートライの代表を務める他、SQL関連書籍の執筆も多数。『MySQL徹底入門』(共著書 / 刊:翔泳社)など。

【修正履歴】ORDER BY句にありました誤記をご指摘により修正いたしました。(2019年11月15日10時30分)

若手ハイキャリアのスカウト転職