MW211 EXIT

devlog
PostgreSQL/一意性制約列の値振り直し
2012年12月21日
一意制約およびNOT NULL制約がある列に値が入っているとして、
その値を全体的に再編成したい場合がある。

でも、一つ一つ更新していたら、昔の値と重複エラーとなってしまったりして
めんどくさい。
NOT NULL制約がなければ一旦NULLにするって方法があるのだが。

んなわけで、一旦、ありえない値に更新してから、新しい値を更新する方法を考える。
例えば「1~99」の値を再編成する場合、
一旦「100~」とかの値に振り直してから、再度「1~99」の値を更新すれば、
昔の値に影響されることなく(重複エラーが発生することなく)
更新ができるというわけだ。

まず考えたのは、最大値に+1していけばいいんじゃないかという案。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│   SET 列 = (SELECT MAX(列) FROM 表) + 1;                                   │
└──────────────────────────────────────┘
しかし、これは都度最大値を計算してくれるわけではなく、
最初の一回しか計算してくれないから例えば全件「100」とかになって
うまくいかない(更新できない)。

これを実現するにはこんなSQL文となる。
┌──────────────────────────────────────┐
│WITH 一時表(キー,                                                           │
│            列) AS (                                                        │
│         SELECT キー,                                                       │
│                (SELECT max(列) FROM 表) + 100                  --最大+100  │
│              + row_number() OVER()                             --連番になる│
│             FROM 表                                                        │
│     )                                                                      │
│UPDATE 表                                                                   │
│    SET 列 = 一時表.列                                                      │
│    FROM 一時表                                                             │
│    WHERE 一時表.キー = 表.キー;                                            │
└──────────────────────────────────────┘
これなら確実だけど、やや複雑だ。

いっそのこと、乱数に頼った方がシンプルかも。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│   SET 列 = 100 + ROUND((RANDOM() * 1000)::numeric, 0);                     │
└──────────────────────────────────────┘
稀に、重複するかもしれないが、その場合は、再度実行するか、
RANDOM()に掛ける値を広げるとよい。
分類:PostgreSQL
PostgreSQL/空欄のソート(3)
2012年12月14日
空欄もNULLも見た目が一緒だから、まとめてしまえ!

ということで、まずは空欄にまとめる方法。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM (SELECT 1 AS "k",'a'   AS "c"  --文字                              │
│    UNION SELECT 2 AS "k",''    AS "c"  --空欄                              │
│    UNION SELECT 3 AS "k",NULL  AS "c"  --NULL                              │
│    ) AS "t"                                                                │
│    ORDER BY COALESCE("c", '') ASC;                                         │
└──────────────────────────────────────┘
「空欄→NULL→文字」の順になる。
ちなにみ四番目に「空欄」を追加してみたが「空欄→空欄→NULL→文字」の順となった。
ま、「空欄→NULL」の部分はすべて等価なので、
第二ソート指定で、任意の順に並び替えるってことになるだろう。

続いてNULLの方にまとめる方法。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM (SELECT 1 AS "k",'a'   AS "c"  --文字                              │
│    UNION SELECT 2 AS "k",''    AS "c"  --空欄                              │
│    UNION SELECT 3 AS "k",NULL  AS "c"  --NULL                              │
│    ) AS "t"                                                                │
│    ORDER BY CASE WHEN LENGTH("c") > 0 THEN "c" ELSE NULL END ASC;          │
└──────────────────────────────────────┘
「文字→空欄→NULL」の順になる。
ちなにみ四番目に「空欄」を追加してみたが「文字→空欄→空欄→NULL」の順となった。
なにやら見えない「空欄→NULL」があるみたい。
といっても、同じ値(NULL)を並び替えても、どうなるか保証されない訳だから、
前述の通りあまり気にしなくてよかろう。
分類:PostgreSQL
PostgreSQL/空欄のソート(2)
2012年12月13日
いつも末尾になる「NULL」を先頭にもってきたい場合は、
「IS NOT NULL ASC」もしくは「IS NULL DESC」を最初に挟めばいい。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM (SELECT 1 AS "k",'a'   AS "c"  --文字                              │
│    UNION SELECT 2 AS "k",''    AS "c"  --空欄                              │
│    UNION SELECT 3 AS "k",NULL  AS "c"  --NULL                              │
│    ) AS "t"                                                                │
│    ORDER BY "c" IS NOT NULL ASC,                                           │
│             "c"             ASC;                                           │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM (SELECT 1 AS "k",'a'   AS "c"  --文字                              │
│    UNION SELECT 2 AS "k",''    AS "c"  --空欄                              │
│    UNION SELECT 3 AS "k",NULL  AS "c"  --NULL                              │
│    ) AS "t"                                                                │
│    ORDER BY "c" IS NULL DESC,                                              │
│             "c"         ASC;                                               │
└──────────────────────────────────────┘
これで「NULL→空欄→文字」となる。

論理型のソート順は「偽→真」なので、NULLと反対の条件にして
NULLだけを偽にしてしまえば、NULLが先頭にくる(ややこしい)という仕組みだ。
分類:PostgreSQL
PostgreSQL/空欄のソート
2012年12月12日
空欄とNULLのソート順もあやふやなので試してみた。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM (SELECT 1 AS "k",'a'   AS "c"  --文字                              │
│    UNION SELECT 2 AS "k",''    AS "c"  --空欄                              │
│    UNION SELECT 3 AS "k",NULL  AS "c"  --NULL                              │
│    ) AS "t"                                                                │
│    ORDER BY "c" ASC;                                                       │
└──────────────────────────────────────┘

  昇順:「空欄→文字→NULL」の順
  降順:「NULL→文字→空欄」の順(昇順の真逆)

という結果となった。

空欄とNULLの区別がぱっとみつかないので、
なんで空欄が先頭と末尾に固まるんだろうという罠にハマってしまいそうだ。
分類:PostgreSQL
PostgreSQL/文字長
2012年12月11日
文字数を取得したい場合には「LENGTH()」を使う。
┌──────────────────────────────────────┐
│SELECT LENGTH('abcあい');                                                →5│
└──────────────────────────────────────┘

文字長を取得したい場合には「OCTET_LENGTH()」を使う。
┌──────────────────────────────────────┐
│SELECT OCTET_LENGTH('abcあい');                                          →9│
└──────────────────────────────────────┘
「UTF-8」環境で実行したので、上記だと「1+1+1+3+3」で「9」となる。
分類:PostgreSQL
PostgreSQL/論理型のソート
2012年12月10日
論理型をソートするとどの順に並ぶのかあやふやなので以下で実験してみた。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM (SELECT TRUE  AS "c"                                               │
│    UNION SELECT FALSE AS "c"                                               │
│    UNION SELECT NULL  AS "c"                                               │
│    ) AS "t"                                                                │
│    ORDER BY "c" ASC;                                                       │
└──────────────────────────────────────┘
「ASC」(昇順)を「DESC」(降順)に置換したりして試したところ…。

  昇順:「FALSE→TRUE→NULL」の順
  降順:「NULL→TRUE→FALSE」の順(昇順の真逆)

という結果となった。

なんか、「TRUE→FALSE」が正順のように錯覚してたなぁ。

ちなみに、「UNION ALL」にして複数件ぐちゃぐちゃにして試してみたが、
上記の結果に従った結果となった(「FALSE…FALSE→TRUE…TRUE→」みたいな感じ)。

ちなみに、どれが根拠になってるんだろう(わからん)。
  ・FALSE   < TRUE
  ・'false' < 'true'
  ・'f'     < 't'
  ・'no'    < 'yes'
  ・'n'     < 'y'
  ・0       < 1
どちらにしろ、FALSEの方が前だわな。
分類:PostgreSQL
IE8/プルダウンメニューの横幅
2012年12月09日
プルダウンメニューを選択しようとすると、横長の文字も全て表示してくれる。
最近のブラウザ(IE9、Firefox、Chromeなど)では当たり前のことでも、
ひと昔前は当たり前じゃなかった(IEだけ?)。

とにかくIE8で文字長の長い選択肢がプルダウンメニューにあると
選択しようとするときに後ろの方が尻切れになってしまう。

これは仕方がない。

JavaScriptで対応できなくはないが、いろいろとめんどくさそうだし
完璧に対応できるかも疑問。

嵐が去る(IE8が絶滅する?)のを待つ他ない?
分類:ブラウザ
PostgreSQL/連番を前詰に振り直す
2012年12月05日
「serial型」もしくは「bigserial型」の列(例えばIDなど)において、
レコードを削除するなどして、歯抜けが発生した場合、
前詰にしたくなる場合がある。

以下がそのやり方。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET 列 = (SELECT COUNT(*)                                               │
│                  FROM 表 t1,                                               │
│                       表 t2                                                │
│                  WHERE t1.列 >= t2.列                                      │
│                    AND t1.列  = 表.列                                      │
│                  GROUP BY t1.列);                                          │
├──────────────────────────────────────┤
│SELECT SETVAL ('AutoNumber用列名', (SELECT COUNT(*) FROM 表), true);        │
└──────────────────────────────────────┘
分類:PostgreSQL
前へ 1 次へ