MW211 EXIT

devlog
PostgreSQL/今日まで連続して…(2)
2012年08月15日
この前の命題の続き。
まず、連続日数を算出してから、判定。
これなら速いしすっきりする。
┌──────────────────────────────────────┐
│SELECT 表.キー1,                                                            │
│       表.キー2                                                             │
│    FROM (SELECT 表.キー1,                                                  │
│                 表.キー2,                                                  │
│                 COUNT(*) AS 数                                             │
│              FROM 表                                                       │
│              WHERE 日付 > COALESCE((SELECT MAX(別表名.日付)                │
│                                         FROM 表 AS 別表名                  │
│                                         WHERE 別表名.キー1 =  表.キー1     │
│                                           AND 別表名.キー2 =  表.キー2     │
│                                           AND 別表名.判定  <> TRUE         │
│                                    ),                                      │
│                                    '-infinity'::timestam)                  │
│                AND 表.判定 = TRUE                                          │
│              GROUP BY 表.キー1,                                            │
│                       表.キー2                                             │
│         ) AS 別々表名                                                      │
│    WHERE 数 >= 規定数                                                      │
└──────────────────────────────────────┘

念には念を入れて、MAX()をORDER BYにすると若干速くなる。
┌──────────────────────────────────────┐
│SELECT 表.キー1,                                                            │
│       表.キー2                                                             │
│    FROM (SELECT 表.キー1,                                                  │
│                 表.キー2,                                                  │
│                 COUNT(*) AS 数                                             │
│              FROM 表                                                       │
│              WHERE 日付 > COALESCE((SELECT 別表名.日付                     │
│                                         FROM 表 AS 別表名                  │
│                                         WHERE 別表名.キー1 =  表.キー1     │
│                                           AND 別表名.キー2 =  表.キー2     │
│                                           AND 別表名.判定  <> TRUE         │
│                                         ORDER BY 別表名.日付 DESC          │
│                                         LIMIT 1                            │
│                                    ),                                      │
│                                    '-infinity'::timestam)                  │
│                AND 表.判定 = TRUE                                          │
│              GROUP BY 表.キー1,                                            │
│                       表.キー2                                             │
│         ) AS 別々表名                                                      │
│    WHERE 数 >= 規定数                                                      │
└──────────────────────────────────────┘
分類:PostgreSQL
PostgreSQL/今日まで連続して…(1)
2012年08月14日
毎日一件判定した履歴があって、これがキーごとに混在している表があるとする。
しかもキーが複合キーだったりして。
┌──────────────────────────────────────┐
│1-1 2012/05/31 ○                                                           │
│1-1 2012/05/30 ×                                                           │
│  :                                                                        │
│1-2 2012/05/31 ○                                                           │
│  :                                                                        │
│2-1 2012/05/31 ○                                                           │
│  :                                                                        │
└──────────────────────────────────────┘
ま、こんな感じ。

さて、直近の数日間、連続して○だったもの(キー)を抽出したい場合のSQL文とは?
┌──────────────────────────────────────┐
│SELECT キー1,                                                               │
│       キー2                                                                │
│    FROM (SELECT t1.キー1,                                                  │
│                 t1.キー2,                                                  │
│                 t1.判定                                                    │
│              FROM 表 AS t1                                                 │
│              WHERE         (t1.キー1, t1.キー2, t1.日付)                   │
│                  IN (SELECT t2.キー1, t2.キー2, t2.日付                    │
│                          FROM 表 AS t2                                     │
│                          WHERE t2.キー1 = t1.キー1                         │
│                            AND t2.キー2 = t1.キー2                         │
│                      ORDER BY t2.日付 DESC                                 │
│                      LIMIT 規定数                                          │
│                     )                                                      │
│         ) AS 別表名                                                        │
│    WHERE 判定 = TRUE                                                       │
│    GROUP BY キー1,                                                         │
│             キー2                                                          │
│    HAVING COUNT(*) = 規定数                                                │
└──────────────────────────────────────┘
相関問い合わせの複合キーバージョン。
う、う、う、遅い。
分類:PostgreSQL
PostgreSQL/MAX()・MIN()とORDER BY&LIMIT 1
2012年08月09日
単純なMAX()やMIN()なら、ORDER BY&LIMIT 1にした方が若干速いらしい。
┌──────────────────────────────────────┐
│SELECT MAX(列) FROM 表;                                                     │
├──────────────────────────────────────┤
│SELECT 列 FROM 表 ORDER BY 列 DESC LIMIT 1;                                 │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│SELECT MIN(列) FROM 表;                                                     │
├──────────────────────────────────────┤
│SELECT 列 FROM 表 ORDER BY 列 ASC LIMIT 1;                                  │
└──────────────────────────────────────┘

大量データの時は一考かも。
ただ、文が長くなるし、他の集合関数と併用できないとか制約はある。
分類:PostgreSQL
PostgreSQL/副問い合わせの数値と文字列
2012年08月02日
以下の構文は両方ともOK
○SELECT (SELECT 1);
○SELECT (SELECT 'A');

でも、以下の構文は後者がエラーとなる
○SELECT 'Z' WHERE 1 = (SELECT 1);
×SELECT 'Z' WHERE 'A' = (SELECT 'A');
なぜだろう?

一旦戻って、出力結果の型を調べた
○SELECT (SELECT 1)          →integer型
○SELECT (SELECT 'A')        →unknown型
文字列はunknown型になっちゃうみたい。

よって、以下のようにキャストしてあげればOK。
○SELECT 'Z' WHERE 'A' = (SELECT 'A')::text;
分類:PostgreSQL
PostgreSQL/書式の罠
2012年06月29日
数値を文字列に変更するには、以下のように「TO_CHAR()」を使う。
┌──────────────────────────────────────┐
│TO_CHAR(列, '0') AS 新名                                                    │
└──────────────────────────────────────┘
でもこうすると、「 1」みたいに先頭にスペースが付加されてしまう

これを回避するには
┌──────────────────────────────────────┐
│TO_CHAR(列, 'FM0') AS 列                                                    │
└──────────────────────────────────────┘
って「FM」をつけてあげればよい。
「1」になる。
分類:PostgreSQL
PostgreSQL/四捨五入の罠
2012年06月24日
「7÷4=1.75」なわけだが、(小数点以下を)四捨五入した場合「2」になるはずだ。
┌──────────────────────────────────────┐
│SELECT ROUND(7 / 4)  →  1                                                  │
└──────────────────────────────────────┘
でも、そうならない。。。

どうやら、浮動小数点とかが絡むと正確性がなくなるらしい(ありがちな話)。

numeric型を使えばよいみたい。
いろいろ試してみた。
┌──────────────────────────────────────┐
│SELECT ROUND(7                   / 4)  →  1(double precision型)  不正確    │
│SELECT ROUND(7::bigint           / 4)  →  1(double precision型)  不正確    │
│SELECT ROUND(7::integer          / 4)  →  1(double precision型)  不正確    │
│SELECT ROUND(7::double precision / 4)  →  2(double precision型)  不正確?  │
│SELECT ROUND(7::real             / 4)  →  2(double precision型)  不正確?  │
├──────────────────────────────────────┤
│SELECT ROUND(7::numeric          / 4)  →  2(numeric型)             正確    │
│SELECT ROUND(7::decimal          / 4)  →  2(numeric型)             正確    │
└──────────────────────────────────────┘
分類:PostgreSQL
PostgreSQL/一定期間の配列を求める
2012年06月15日
例えば、本日の11:30から12:29までの「年月日時分(yyyymmddhhii)」の文字列を
配列で求めたい場合、どうすればよいか。

「generate_series()」という配列を生成する便利な関数があるので、
以下のように編集してあげればよい。
┌──────────────────────────────────────┐
│SELECT to_char(current_date, 'yyyymmdd') || CASE WHEN generate_series < 0   │
│         THEN to_char(generate_series + 60, 'FM1100')                       │
│         ELSE to_char(generate_series     , 'FM1200')                       │
│       END AS "yyyymmddhhii"                                                │
│    FROM generate_series(-30, 29, 1);                                       │
└──────────────────────────────────────┘

しかし、「generate_series()」は日時のループもできるので、直接以下でもOK。
┌──────────────────────────────────────┐
│SELECT to_char(current_date, 'yyyymmdd')                                    │
│    || to_char(generate_series, 'FMhhmi') AS "yyyymmddhhii"                 │
│    FROM generate_series(TIMESTAMP '2001-01-01 11:30:00',                   │
│                         TIMESTAMP '2001-01-01 12:29:00',                   │
│                         '1 minute')                                        │
└──────────────────────────────────────┘

で、本日の11:30から12:29までをループさせるという完成形は以下のとおり。
┌──────────────────────────────────────┐
│SELECT to_char(generate_series, 'yyyymmddhhmi') AS "yyyymmddhhii"           │
│    FROM generate_series(current_date + interval '11:30',                   │
│                         current_date + interval '12:29',                   │
│                         interval '00:01')                                  │
└──────────────────────────────────────┘
これは便利。
分類:PostgreSQL
PostgreSQL/本日の正午を求める
2012年06月14日
┌──────────────────────────────────────┐
│SELECT CURRENT_DATE + INTERVAL '12:00';                                     │
└──────────────────────────────────────┘

他の時刻も自由自在。
┌──────────────────────────────────────┐
│SELECT CURRENT_DATE + INTERVAL '13:30:59';                                  │
└──────────────────────────────────────┘
分類:PostgreSQL
PostgreSQL/最大値を更新(1)
2012年06月13日
「更新表.最大」に「入力表.値」を更新しようとするのだが、
「入力表.値」が「更新表.最大」よりも大きい時という条件が付く場合。
(最大値を随時比較して更新していく場合などがこのパターンとなるだろう)
┌──────────────────────────────────────┐
│UPDATE 更新表                                                               │
│  SET 最大 = COALESCE((SELECT 入力表.値                                     │
│                         FROM 入力表                                        │
│                         WHERE 入力表.キー = 更新表.キー                    │
│                           AND (入力表.値 > 更新表.最大                     │
│                             OR 更新表.最大 IS NULL)                        │
│                      ),                                                    │
│                      最大);                                                │
└──────────────────────────────────────┘

「入力表.値」が複数あって最大値を集計した上でという場合には以下の通り。
┌──────────────────────────────────────┐
│UPDATE 更新表                                                               │
│  SET 最大 = COALESCE((SELECT MAX(入力表.値)                                │
│                         FROM 入力表                                        │
│                         WHERE 入力表.キー = 更新表.キー                    │
│                         HAVING MAX(入力表.値) > 更新表.最大                │
│                             OR 更新表.最大 IS NULL                         │
│                      ),                                                    │
│                      最大);                                                │
└──────────────────────────────────────┘

もしかしてもっと簡単な方法がある?
分類:PostgreSQL
PostgreSQL/数値を文字列化
2012年06月07日
PostgreSQLで数値を文字列化するには、「to_char()」を使ったりする。
┌──────────────────────────────────────┐
│to_char(数値, '99')                                                         │
└──────────────────────────────────────┘

でも、書式を明記しなければならず、以下のような場合はエラーとなる。
┌──────────────────────────────────────┐
│to_char(数値)                                                               │
└──────────────────────────────────────┘

一方、文字列結合「||」を使うと、数値も文字列に変換してくれる。
┌──────────────────────────────────────┐
│数値 || 数値                                                                │
└──────────────────────────────────────┘

ということで、以下のように空文字と結合させれば、数値を書式なしで文字列化できる。
┌──────────────────────────────────────┐
│数値 || ''                                                                  │
└──────────────────────────────────────┘

でも、なんかこれって裏技っぽい。

キャストしてしまうって手もあるが、これも裏技っぽい。
┌──────────────────────────────────────┐
│数値::text                                                                  │
└──────────────────────────────────────┘

「to_char(数値, '')」とかしてみてもダメ。

ま、そんなもんなのかな。。。
分類:PostgreSQL
前へ 1 2 3 4 5 6 7 8 9 10 11 次へ