MW211 EXIT

devlog
SQL/値を参照して更新するみたいなこと
2011年12月14日
値を加算するSQL文は以下の通り。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET 列 = 列 + 値                                                        │
│    WHERE 条件;                                                             │
└──────────────────────────────────────┘
SELECTで読み出して、プログラム的に加算して、UPDATEで書き込む、
みたいな処理は不要で、一発で加算できるわけだ。
これなら排他処理が軽減(単体としては不要)される。

もちろん、減算とかにも応用できる。
分類:SQL
MySQL/欠番IDに設定する際に重複チェック
2011年12月13日
適当な欠番「id」に「値」を設定するとすると、以下のような感じになる。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET `id` = 値                                                           │
│    WHERE `id` IS NULL                                                      │
│    ORDER BY rand()                                                         │
│    LIMIT 1;                                                                │
└──────────────────────────────────────┘

「id」がユニークキー(たいていは主キー)で、
ひょっとしてその値が既に設定されているとまずいので
既に存在しないことを条件追加して相関副問い合わせ化したら
以下のような感じになった。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET `id` = 値                                                           │
│    WHERE `id` IS NULL                                                      │
│      AND NOT EXISTS (SELECT `id`                                           │
│                          FROM 表                                           │
│                          WHERE `id` = 値                                   │
│                     )                                                      │
│    ORDER BY rand()                                                         │
│    LIMIT 1;                                                                │
└──────────────────────────────────────┘
でも、エラーになります。
「#1093 - You can't specify target table '表' for update in FROM clause」

要は副問い合わせの中に主問い合わせと同じ表を使えないらしい。

仕方ないのでとりあえず、参照してから条件分岐で更新することにした。
なんかいい方法はないものか。
分類:MySQL
MySQL/サブ件数をマージする
2011年12月12日
先日にも触れたが、「LEFT JOIN」って直積なのをついつい忘れがちになる。
メインデータを一回のSQL発行で取得して、
それをループして一件ずつサブデータをSQL発行で取得してマージしていく…、
みたいな処理を一回のSQL発行でできるのが「LEFT JOIN」なのかなと錯覚してしまう。
当然、名称取得などサブデータが一件の場合はその通りなのだが、
カウントした件数をマージしたりする場合は注意が必要だ。

これはOK。
┌──────────────────────────────────────┐
│SELECT メイン表.ID,                                                         │
│       サブ表.サブ名称                                                      │
│    FROM メイン表                                                           │
│        LEFT JOIN サブ表                                                    │
│          ON サブ表.ID = メイン表.サブID;                                   │
└──────────────────────────────────────┘
サブ名称を参照するケースだ。

これはギリギリOK。
┌──────────────────────────────────────┐
│SELECT メイン表.ID,                                                         │
│       COUNT(サブ表.ID) AS サブ該当件数                                     │
│    FROM メイン表                                                           │
│        LEFT JOIN サブ表                                                    │
│          ON サブ表.キーID = メイン表.サブキーID                            │
│    GROUP BY メイン表.ID;                                                   │
└──────────────────────────────────────┘
サブ表中にサブキーIDに該当するものが何件あるかをマージするケース。

でも、これはNG、件数が二つになったらNG。
┌──────────────────────────────────────┐
│SELECT メイン表.ID,                                                         │
│       COUNT(サブ表1.ID) AS サブ1該当件数,                                  │
│       COUNT(サブ表2.ID) AS サブ2該当件数                                   │
│    FROM メイン表                                                           │
│        LEFT JOIN サブ表1                                                   │
│          ON サブ表1.キーID = メイン表.サブ1キーID                          │
│        LEFT JOIN サブ表2                                                   │
│          ON サブ表2.キーID = メイン表.サブ2キーID                          │
│    GROUP BY メイン表.ID;                                                   │
└──────────────────────────────────────┘
サブ1とサブ2で各々で件数を算出してくれるかと思いきや、直積により、
それぞれの該当件数が両者の掛け算の結果(つまり同一値)になってしまうのだ。

対抗策1、DISTINCTをつける。
┌──────────────────────────────────────┐
│SELECT メイン表.ID,                                                         │
│       COUNT(DISTINCT サブ表1.ID) AS サブ1該当件数,                         │
│       COUNT(DISTINCT サブ表2.ID) AS サブ2該当件数                          │
│    FROM メイン表                                                           │
│        LEFT JOIN サブ表1                                                   │
│          ON サブ表1.キーID = メイン表.サブ1キーID                          │
│        LEFT JOIN サブ表2                                                   │
│          ON サブ表2.キーID = メイン表.サブ2キーID                          │
│    GROUP BY メイン表.ID;                                                   │
└──────────────────────────────────────┘
直積に対抗するにはDISTINCTとばかりに、各々にDISTINCTをつける。
こんなところにDISTINCTを置けるのか不安だったが意外にいける。

対抗策2、サブクエリとする。
┌──────────────────────────────────────┐
│SELECT メイン表.ID,                                                         │
│       (SELECT COUNT(サブ表1.ID)                                            │
│            FROM サブ表1                                                    │
│            WHERE サブ表1.キーID = メイン表.サブ1キーID                     │
│       ) AS サブ1該当件数,                                                  │
│       (SELECT COUNT(サブ表2.ID)                                            │
│            FROM サブ表2                                                    │
│            WHERE サブ表2.キーID = メイン表.サブ2キーID                     │
│       ) AS サブ2該当件数                                                   │
│    FROM メイン表;                                                          │
└──────────────────────────────────────┘
メインデータに対してサブデータをマージするというイメージには、
こっちの方が近いのだろう。
対抗策1だと直積で一旦メインデータを増殖させて、GROUP BYで収束させているが
これだとメインデータはそのままだ。
それにしても()の中に()の外側のメイン表が突然出てくる感じがして
若干違和感があった(JOINしてないから)、でもサブクエリってそんなもの。

対抗策3、UNIONを使う力業。
┌──────────────────────────────────────┐
│SELECT 新メイン表.ID,                                                       │
│       SUM(新メイン表.サブ1該当件数) AS サブ1該当件数,                      │
│       SUM(新メイン表.サブ2該当件数) AS サブ2該当件数                       │
│    FROM (SELECT メイン表.ID,                                               │
│                 NULL              AS サブ1該当件数,                        │
│                 NULL              AS サブ2該当件数                         │
│               FROM メイン表                                                │
│          UNION ALL                                                         │
│          SELECT メイン表.ID,                                               │
│                 COUNT(サブ表1.ID) AS サブ1該当件数,                        │
│                 NULL              AS サブ2該当件数                         │
│               FROM メイン表,                                               │
│                    サブ表1                                                 │
│               WHERE メイン表.サブ1キーID = サブ表1.キーID                  │
│               GROUP BY メイン表.ID                                         │
│          UNION ALL                                                         │
│          SELECT メイン表.ID,                                               │
│                 NULL              AS サブ1該当件数,                        │
│                 COUNT(サブ表2.ID) AS サブ2該当件数                         │
│               FROM メイン表,                                               │
│                    サブ表2                                                 │
│               WHERE メイン表.サブ2キーID = サブ表2.キーID                  │
│               GROUP BY メイン表.ID                                         │
│         ) AS 新メイン表                                                    │
│    GROUP BY 新メイン表.ID;                                                 │
└──────────────────────────────────────┘
こんな感じかな(動作確認してないからちょっと違うかも)。
対抗策3はあくまで余談です。
分類:MySQL
MySQL/ランダムで複数の欠番に埋める
2011年12月11日
「id」が「0」(欠番)の適当な5件を「1」にするSQL文は以下の通り。
┌──────────────────────────────────────┐
│UPDATE `表`                                                                 │
│    SET `id` = '1'                                                          │
│    WHERE `id` = '0'                                                        │
│    ORDER BY rand()                                                         │
│    LIMIT 5;                                                                │
└──────────────────────────────────────┘
UPDATEでも「ORDER BY rand()」と「LIMIT」が使えるのは便利かも。
分類:MySQL
MySQL/WHERE句のNULL
2011年12月10日
ある列がNULLでないものを抽出するSQL文。

┌──────────────────────────────────────┐
│SELECT * FROM 表 WHERE 列 IS NOT NULL;                                      │
└──────────────────────────────────────┘
これだとOK。

でも、これだと(NULLでない行があっても)「該当なし」になってしまう。
┌──────────────────────────────────────┐
│SELECT * FROM 表 WHERE 列 <> NULL;                                          │
└──────────────────────────────────────┘

NULLじゃないんだからいいと思ったんだけどなぁ…
やっぱり、「IS NOT NULL」ってのがあるんだから、そう書かないとダメみたいね。
気をつけないと。

「ID=0」のつもりで「ID=NULL」を変数で使ってるケースは結構あるもんだ。
こんな場合、SQL文を使う瞬間は注意です。
分類:MySQL
セレクタの灯台もと暗し
2011年12月09日
こういう階層になってて…
┌──────────────────────────────────────┐
│<div id="a">                                                                │
│  <div id="aa">                                                             │
└──────────────────────────────────────┘
「ID="a"」の子セレクタ「ID="aa"」を指定したいって時に出くわした。

┌──────────────────────────────────────┐
│#a > #aa                                                                    │
└──────────────────────────────────────┘
とかかな?と悩んだが…

IDって親だろう子だろうが全体で一意なので
┌──────────────────────────────────────┐
│#aa                                                                         │
└──────────────────────────────────────┘
で、いいんです。

こんな単純なことだが、いろいろやってると混乱してしまうのだ。
手を読みすぎて二歩を犯してしまったり、合併の繰り返しで
自社株を大量に保有してしまうようなもんだ。(例えがわかりにくい?)
分類:CSS、注意、jQuery
PHP/配列の件数を指定しての抽出
2011年12月08日
┌──────────────────────────────────────┐
│$array = array(1, 2, 3, 4, 5);                                              │
└──────────────────────────────────────┘
上記みたいな配列があって、先頭から 3件だけ抽出したい場合、どうするか?

┌──────────────────────────────────────┐
│$result = array();                                                          │
│for ($i = 0; $ < 3; $i++) {                                                 │
│  $result[$i] = $array[$i];                                                 │
│}                                                                           │
└──────────────────────────────────────┘
こんな感じ?

いやいや一発でできるんです。
┌──────────────────────────────────────┐
│$result = array_slice($array, 0, 3);                                        │
└──────────────────────────────────────┘

すごいぞ、「array_slice()」!

ちなみに、元の配列に3件以上なくても(エラーなく)動作してくれます
#この場合、当然ながら元の配列と結果は同じになりますね
やっぱりすごいぞ、「array_slice()」!
分類:PHP配列
JSON/配列
2011年12月07日
JSONで配列を扱う時は
┌──────────────────────────────────────┐
│{"a[0]":"a","a[1]":"b","a[2]":"c"}                                          │
└──────────────────────────────────────┘
…なんかじゃなくて(でもいいけど)、

こう!
┌──────────────────────────────────────┐
│{"a":["a","b","c"]}                                                         │
└──────────────────────────────────────┘
分類:JSON
PHP/ファイル一覧
2011年12月06日
あるディレクトリ配下のファイル一覧を取得したい場合には
以下のような感じで取得できる。
┌──────────────────────────────────────┐
│$dir = 'C:\…/data/';                                                       │
│$return = array();                                                          │
│if (is_dir($dir)) {                                                         │
│  if ($handle = opendir($dir)) {                                            │
│    while (false !== ($file = readdir($handle))) {                          │
│      if (!is_dir($dir . $file)) {                                          │
│        $return[] = $file;                                                  │
│      }                                                                     │
│    }                                                                       │
│  }                                                                         │
│  closedir($handle);                                                        │
│}                                                                           │
│print_r($return);                                                           │
└──────────────────────────────────────┘
あくまで、ファイルパスがわかっている場合のお話。
分類:PHP
PHP/Index_of画面の活用
2011年12月05日
「http://…/data/」とかってブラウザから指定した時に
その配下に「index.htm」とかがないと、ファイル一覧が表示される場合がある。
「Index of ~」って画面だ。

これは情報漏洩の元凶みたいなもんで、忌み嫌われている。
ネットで検索しても、表示させない方法ばかりがとりざたされている。

表示させない方法は、「.htaccess」に以下を記述して、そのフォルダに置けばよい。
┌──────────────────────────────────────┐
│Options -Indexes                                                            │
└──────────────────────────────────────┘
たぶん、「htpd.conf」とかに設定した方がいいのだろうけど、まずはここまで。

では、これを表示させたい場合は?(あまのじゃく!)
┌──────────────────────────────────────┐
│Options +Indexes                                                            │
└──────────────────────────────────────┘
記述をこう書き換えればよい(「-」が「+」になっただけ)。

さて、表示させてどうするの?
ま、PHPでhtmファイル一覧でも取得してみるか。(対象が「http://…/data/」の場合)
┌──────────────────────────────────────┐
│$dir = 'http://…/data/';                                                   │
│$return = array();                                                          │
│$source_list = @file($dir);                                                 │
│if ($source_list) {                                                         │
│  foreach ($source_list as $value) {                                        │
│    if (preg_match('/\.htm\"/', $value)) {                                  │
│      $file = trim(preg_replace('/^.*href\=\"|\.htm\".*$/', '', $value))    │
│            . '.htm';                                                       │
│      $return[] = $file;                                                    │
│    }                                                                       │
│  }                                                                         │
│}                                                                           │
│print_r($return);                                                           │
└──────────────────────────────────────┘
ま、他にバリエーションはありそうだけど…。

「Index of ~」画面の仕様も明確じゃないし、
そもそもセキュリティ的に?なので、お遊び程度に。
分類:PHP
前へ 1 … 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 … 156 次へ