LoginSignup
51

More than 5 years have passed since last update.

1分で地味に効く SQL

Last updated at Posted at 2015-12-08

はじめに

この Tips は初中級者向けです。

業務で SQL を書く人は多いと思いますが、その編集を行う際に使うエディタはこれといったデファクトスタンダードがなかったり別の言語の中で文字列として扱うことも少なからずあったりして、その記法などについて暗中模索をしている方が多いのではないでしょうか。

1分で理解できて、地味に効いてくる SQL の Tips を、__ひとつだけだと寂しいので__3つご紹介します。

  1. 動的に検索条件が決まる
  2. 結合条件は Join 句を使う
  3. テーブル名をキーワードと同じ行に書く

動的に検索条件が決まる

プログラムの中で動的に SQL 文を組み立てる人は多いのではないでしょうか。「検索条件が指定されなければ全件検索」という SQL を組み立てる際に、下記のように WHERE 句をつけるかつけないかも動的にしていませんか?

Before
// PHP のコード例です。
$sql = "
    SELECT
        *
    FROM user_info
    ";

$and = " WHERE ";

// 検索条件に名前が指定された場合
if ($user_name != "") {
    $sql .= $and. " user_name LIKE ". $user_name;
    $and = " AND ";
}

// 検索条件に年齢が指定された場合
if ($age != "") {
    $sql .= $and. " age = ". $age;
    $and = " AND ";
}

検索条件を追加する処理が多く複雑になってくるといつ AND が入ってくるのか分らなくなってきます。検索条件ごとに処理を入れなくてはなりません。また全件検索が指定される場合は WHERE そのものが不要になる場合も。
そこで最初に「必ず真になる式」を書いておき、続く条件には必ず AND を書くようにします。これだけでかなりコードが省略できます。
また、デバッグする際に条件を一つずつコメントアウトしたりするのにも便利です。
具体的には下記のようなコードになります。

After

$sql = "
    SELECT
        *
    FROM user_info
    WHERE 1=1 -- <-ここがポイントです
    ";

// 検索条件に名前が指定された場合
if ($user_name != "") {
    $sql .= "   AND user_name LIKE ". $user_name;
}

// 検索条件に年齢が指定された場合
if ($age != "") {
    $sql .= "   AND age = ". $age;
}

この Tips はどこかのサイトで見たものなのですが、どこだったのか失念してしまいました。

結合条件は必ず Join 句を使う

次のような SQL を書く人は多いでしょう。参考書などに書かれている最初のサンプルがそうですから。

Before
SELECT 
    u.name,
    a.zip_code
FROM user_info     u,
     address_info  a
WHERE u.user_id = a.user_id
    AND u.age < 20

私は、以下のように Inner Join を使って書いています。必ずそうしています。

After
SELECT
    u.name,
    a.zip_code
FROM  user_info     u
    INNER JOIN  address_info  a
        ON  u.user_id = a.user_id
WHERE  u.age < 20

「タイプ量が増えるだけで結果が同じ」と、あまりメリットが感じられないかもしれません。
しかしながら「結合のための条件を From 句の下に」「抽出のための条件を Where 句の下に」分離することができます。
結合するテーブルが増えてきてデバッグに苦労したり、忘れた頃にやってくる保守の時期になると、そのメリットが見えてくるのではないでしょうか。

テーブル名をキーワードと同じ行に書く

複数行に渡るような大きな SQL を書く場合、いろいろな記法があり現在までコレと言った決め手が無いのが悩みどころです。大きなシステムの保守を引き継いだ際に、テーブル名で grep した時に、どこでレコードを挿入したり削除したりしているかがわかるように INSERT INTODELETEUPDATEFROM らとテーブル名は同じ行に書いておいた方が良いと思いました。あまり美しくはないですが...。

Insert文
INSERT INTO table_name
(...
Delete文
DELETE table_name 
WHERE...
Update文
UPDATE table_name 
SET...
Select文
SELECT
    *
FROM table_name...

ま、これもテーブル名が変数に入ってたりすると漏れは出てしまうのですが。

免責

コード例は説明のために極端に単純化しています。コード例以外の部分で基本的な事柄の説明が省略されているかもしれません。

【追記】
「説明のため極端に単純化」が通じない人が居たようなので追記します。最初に「中級者」と書いたのに、確かにそれは不親切でもありました。
最初の Tips のように、文字列結合で SQL に値を渡してはいけません。プリペアドクエリを使ってください。例は説明用に極端な単純化をしているだけです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51