MW211 EXIT

devlog
SQL/NULLと条件式
2012年05月28日
列がNULLだった場合、以下には該当しない。
┌──────────────────────────────────────┐
│SELECT * FROM 表 WHERE 列 > 0;                                              │
└──────────────────────────────────────┘
これはわかる気がする。

で、ほぼ反対の以下にも該当しない。
┌──────────────────────────────────────┐
│SELECT * FROM 表 WHERE 列 < 1;                                              │
└──────────────────────────────────────┘
つまり、0ではない。これもわかる。

そして、最初の正反対である以下にも該当しない。
┌──────────────────────────────────────┐
│SELECT * FROM 表 WHERE NOT(列 > 0);                                         │
└──────────────────────────────────────┘
もう、何にも該当しないみたい。

つまり、これでも該当なし。
┌──────────────────────────────────────┐
│SELECT * FROM 表 WHERE (列 > 0) OR  (NOT(列 > 0));                          │
└──────────────────────────────────────┘

NULLについては、WHERE句に列を指定した時点で負けみたいだね。
分類:SQL
PHP/SQL文のIN句をつくる(2)
2012年02月18日
┌──────────────────────────────────────┐
│$where = array(1,,,4,,5);                                                   │
└──────────────────────────────────────┘
上記のように抽出条件に空値が混じっている場合、これを除外するには
以下の方法が有効だ。
┌──────────────────────────────────────┐
│$in = implode(',', array_filter($where, 'strlen'))             →  「1,4,5」│
└──────────────────────────────────────┘
「array_filter(,'strlen')」は文字長のある配列要素のみを抽出してくれる。
それぞれを「strlen()」にて変換した結果、
値が0でないものを抽出してくれるという仕組みだ。
分類:PHP、SQL
PHP/SQL文のIN句をつくる(1)
2012年02月17日
┌──────────────────────────────────────┐
│$where = array(1,4,5);                                                      │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│SELECT 列                                                                   │
│    FROM 表                                                                 │
│    WHERE id IN (1,4,5);                                                    │
└──────────────────────────────────────┘
抽出したいIDを配列にあらかじめ格納しておいて、
そのIDに該当するものをSQL文で取得する場合、
配列をimplodeで一直線に並べて、SQL文に代入したやればよい
┌──────────────────────────────────────┐
│$in = implode(',', $where)                                     →  「1,4,5」│
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│SELECT 列                                                                   │
│    FROM 表                                                                 │
│    WHERE id IN ({$in});                                                    │
└──────────────────────────────────────┘

ちなみに、文字列の場合、「'」で囲う必要があるが、
これについては以下のようにしてやればよい。
┌──────────────────────────────────────┐
│$in = "'" . implode("','", $where) . "'"                 →  「"1","4","5"」│
└──────────────────────────────────────┘
分類:PHP、SQL
SQL/相関問い合わせ
2012年02月08日
例えば、個人が所属している団体名を表示させるSQLの場合、以下のような感じになる。
┌──────────────────────────────────────┐
│SELECT 個人.名称,                                                           │
│       団体.名称                                                            │
│    FROM 個人                                                               │
│        LEFT JOIN 団体                                                      │
│          ON 団体.団体コード = 個人.団体コード                              │
└──────────────────────────────────────┘
じゃ、無所属の個人のみを抽出したい場合は?となると、
以下のようにWHERE句をつけると、簡単に移行できる。
┌──────────────────────────────────────┐
│SELECT 個人.名称                                                            │
│    FROM 個人                                                               │
│        LEFT JOIN 団体                                                      │
│          ON 団体.団体コード = 個人.団体コード                              │
│    WHERE 団体.主キー IS NULL;                                              │
└──────────────────────────────────────┘
しかし、この手抜きSQL文は本格的になると
結構、問い合わせに時間がかかってしまうようだ。

で、この場合は、相関問い合わせに移行してしまった方がよいようだ。
┌──────────────────────────────────────┐
│SELECT 個人.名称                                                            │
│    FROM 個人                                                               │
│    WHERE NOT EXISTS (SELECT 団体.主キー                                    │
│                          FROM 団体                                         │
│                          WHERE 団体.団体コード = 個人.団体コード           │
│                     );                                                     │
└──────────────────────────────────────┘
結果はどちらも同じなので、簡単な前者のままにしてしまって
後で、遅い遅いと問題になるかもしれないから注意。
分類:SQL
SQL/値を参照して更新するみたいなこと
2011年12月14日
値を加算するSQL文は以下の通り。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET 列 = 列 + 値                                                        │
│    WHERE 条件;                                                             │
└──────────────────────────────────────┘
SELECTで読み出して、プログラム的に加算して、UPDATEで書き込む、
みたいな処理は不要で、一発で加算できるわけだ。
これなら排他処理が軽減(単体としては不要)される。

もちろん、減算とかにも応用できる。
分類:SQL
PHP/配列でSQL抽出
2011年10月24日
配列$idに抽出したいIDを格納しておいて、
これを元にSELECT文を発行したい場合には、以下のような感じに
「implode()」で「,」区切り一直線に連結して「WHERE IN()」の中にぶち込むとよい。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM 表                                                                 │
│    WHERE "ID" IN ({implode(',', $id)});                                    │
└──────────────────────────────────────┘
#これはあくまでイメージで、実際には「.」とかで文字列結合してください

すると以下のようになるわけだ。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM 表                                                                 │
│    WHERE "ID" IN (1,2,3);                                                  │
└──────────────────────────────────────┘

しかし、配列$idに一件もIDがないと、以下のようになって当然エラー。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM 表                                                                 │
│    WHERE "ID" IN ();                                                       │
└──────────────────────────────────────┘

ということで、これを回避するには、「WHERE IN()」の部分に
ありえない値を入れるのが手っ取り早いのではないだろうか。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM 表                                                                 │
│    WHERE "ID" IN (0);                                                      │
└──────────────────────────────────────┘
※IDが「1」から始まり「0」がないことが前提

万全を期すならば「WHERE IN()」の部分を「WHERE FALSE」に
(条件分岐で)置換してあげるという手もある
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM 表                                                                 │
│    WHERE FALSE;                                                            │
└──────────────────────────────────────┘

間違っても、WHERE句毎削除してはいけない。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM 表;                                                                │
└──────────────────────────────────────┘
全件ひっかかってしまう(該当ありになってしまう)からだ。
分類:SQL、PHP配列
SQL/左外部結合の勘違い
2011年10月12日
なにも左外部結合に限った話ではなく、右外部結合も同じなのだが
右外部結合はあんまり使わないので、左外部結合で話をすすめる。

左外部結合を使うシチュエーションというのは、
キーと値が1対1の定数的な関係のテーブルを参照する場合が多い。

コード(キー)はわかっているので、それを文字(値)に変換したい場合だ。
例えば、「1→北海道」「2→青森県」みたいな感じ。

なのでたいていの場合、キーは主キー(もしくは一意キー)であり、
該当するレコードは1件(もしくは0件)だ。

これに慣れてしまうと、左外部結合は1件だけキーを値に変換してくれる
変換関数的なイメージをもってしまう。

もし、キーが同一なものが2件あった場合は?
(例えば「201→青森市」「201→盛岡市」みたいな場合)

先頭の1件だけをひっぱってきてくれる…なんて勘違いしてませんか?

いやいや、SQLの結合の基本は直積なので、左外部結合も直積なのです。
つまり参照元のレコードが2倍に増殖してしまう。

ま、あんまりそんなシチュエーションには出くわさないのだけど
たまにだから、驚いてしまう。
分類:SQL
定数の値
2011年09月25日
定数の値はたいてい「1,2,3…」とかだ。
┌─┬─┐
│ 1│男│
├─┼─┤
│ 2│女│
└─┴─┘
みたいな感じ。

ふと、数値じゃなくてもいいんじゃね?とか思い、「male、female」の頭文字をとって
┌─┬─┐
│m │男│
├─┼─┤
│f │女│
└─┴─┘
な~んて定義してみる。

同じじゃん。こっちの方が直感的でわかりやすいし。オレって天才。
なんて思っていると実は落とし穴に嵌っていることに後から気づく。

そう、ソート順のキーに指定した場合「女→男」の順なってしまうのだ。

定数の値は、並び順の番号と心得るべし。

#順番については男尊女卑ではありませんのであしからず
分類:SQL、注意、設計
SQL/INSERT文に一意制約をつける
2011年09月24日
一意属性(UNIQUE)をつけたいのにつけられない項目があるとする。
例えば、削除区分とかを使って削除レコードを履歴として残している場合の
実質的なキー項目とかの場合だ。
#削除レコードを除いて中では一意になる項目とかのこと

ま、とにかく事情があって一意属性はつけられないが
一意であって欲しい場合、INSERT時に制約をかけるとするなら
一旦SELECTで読み込んで存在を確認した上で
存在していない場合のみINSERTするとかいう処理になると思う。

これを一回のSQL文で実現させることができないものかと考えていたのだが
「相関副問い合わせ」ってやつを使えばできてしまうのだ。
┌──────────────────────────────────────┐
│INSERT INTO 出力表 (出力列)                                                 │
│    SELECT 入力列                                                           │
│        FROM 入力表                                                         │
│        WHERE 条件                                                          │
│          AND NOT EXISTS (SELECT *                                          │
│                              FROM 出力表                                   │
│                              WHERE 出力.出力列 = 入力表.入力列);           │
└──────────────────────────────────────┘

「副問い合わせ」までで挫折して「相関副問い合わせ」なんかとは縁がなかったが
こうやって使ってみると便利なものだ。(ってこの使い方が正しいのかはやや不安)

★この方法には問題があることがわかりました、後日加筆修正します
分類:SQL
SQL/呉越同舟?Ⅱ
2011年09月23日
以前、まったく違う列を結合したかのように取得する方法を取り上げた。
┌──────────────────────────────────────┐
│SELECT 表1.列11,                                                            │
│       表2.列21                                                             │
│  FROM 表1,                                                                 │
│       表2                                                                  │
│  WHERE 表1.列11 = '値'                                                     │
│    AND 表2.列21 = '値';                                                    │
└──────────────────────────────────────┘
上記のようにすれば、あたかも以下の結果を横に並べたようになるのである。
#但し、双方ともに一件ずつ該当し、結果が一件になるような場合が望ましい
┌──────────────────────────────────────┐
│SELECT 表1.列11                                                             │
│  FROM 表1                                                                  │
│  WHERE 表1.列11 = '値';                                                    │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│SELECT 表2.列21                                                             │
│  FROM 表2                                                                  │
│  WHERE 表2.列21 = '値';                                                    │
└──────────────────────────────────────┘

これに集合関数が絡んでくるとひと工夫必要なことがわかったので追記する。
┌──────────────────────────────────────┐
│SELECT 表1.列11                                                             │
│       MAX(表2.列21)                                                        │
│    FROM 表1,                                                               │
│         表2                                                                │
│    WHERE 表1.列11 = '値'                                                   │
│      AND 表2.列22 = '値'                                                   │
│    GROUP BY 表1.列11;                                                      │
└──────────────────────────────────────┘
当然ながら、結果一件なのだが「GROUP BY」がないと建て前として
集合関数との整合性がとれないので、これは(必須な場合は)必須みたいだ。
分類:SQL
前へ 1 2 3 4 5 6 次へ