MW211 EXIT

devlog
SQL/相関副問い合わせの階層
2014年12月26日
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM 親表                                                               │
│    WHERE EXISTS (                                                          │
│        SELECT * FROM (                                                     │
│          SELECT * FROM (                                                   │
│            SELECT * FROM (                                                 │
│              SELECT * FROM (                                               │
│                SELECT * FROM (                                             │
│                  SELECT * FROM (                                           │
│                    SELECT * FROM (                                         │
│                      SELECT * FROM (                                       │
│                          SELECT *                                          │
│                              FROM 子表                                     │
│                              WHERE 子表.列 = 親表.列                       │
│                      ) AS [a]                                              │
│                    ) AS [a]                                                │
│                  ) AS [a]                                                  │
│                ) AS [a]                                                    │
│              ) AS [a]                                                      │
│            ) AS [a]                                                        │
│          ) AS [a]                                                          │
│        ) AS [a]                                                            │
│    );                                                                      │
└──────────────────────────────────────┘
上記のようなのもいける。

親表は、子表が深くても効くようだ。
分類:SQL
SQL/連続するデータにグループ番号
2014年12月01日
同じ属性が連続するものをグルーピングしたい場合のSQL。
  ○→1
  ○→1
  ×→2
  ×→2
  ○→3
┌──────────────────────────────────────┐
│SELECT 表.並び順,                                                           │
│       表.属性,                                                             │
│       COUNT(*) AS グループ番号                                             │
│    FROM 表                                                                 │
│        LEFT JOIN (                                                         │
│            SELECT 基準表.*                                                 │
│                FROM 表 AS 基準表                                           │
│                    LEFT JOIN 表 AS 直前表                                  │
│                      ON  直前表.並び順 = (SELECT MAX(並び順)               │
│                                               FROM 表                      │
│                                               WHERE 並び順 < 基準表.並び順)│
│                      AND 直前表.属性 <> 基準表.属性                        │
│                WHERE 基準表.並び順 = (SELECT MIN(並び順) FROM 表)          │
│                   OR 直前表.並び順 IS NOT NULL                             │
│        ) AS 境界                                                           │
│          ON 境界.並び順 <= 表.並び順                                       │
│    GROUP BY 表.並び順,                                                     │
│             表.属性                                                        │
│    ORDER BY 表.並び順 ASC;                                                 │
└──────────────────────────────────────┘
分類:SQL
SQL/順番再計算
2014年11月14日
親キーごとに基準項目を元に、連番を昇順に振り直す場合は、以下の通り。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET 順番項目 = (                                                        │
│        SELECT COUNT(*)                                                     │
│            FROM 表 AS 順番調査                                             │
│            WHERE 順番調査.親キー   =  表.親キー                            │
│              AND 順番調査.基準項目 <= 表.基準項目                          │
│    );                                                                      │
└──────────────────────────────────────┘

但し、基準項目がグループ内で一意でなければ、同順位が発生してしまうので
便宜上、一意キー(主キーなど)で、以下のように重複を分散させる場合あり。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET 順番項目 = (                                                        │
│        SELECT COUNT(*)                                                     │
│            FROM 表 AS 順番調査                                             │
│            WHERE 順番調査.親キー = 表.親キー                               │
│              AND (順番調査.基準項目 < 表.基準項目                          │
│               OR  (順番調査.基準項目 =  表.基準項目                        │
│                AND 順番調査.一意キー <= 表.一意キー))                      │
│    );                                                                      │
└──────────────────────────────────────┘
分類:SQL
SQL/完全外部結合でNULL比較
2014年11月08日
「FULL JOIN」で完全外部結合し、NULLも含めた比較をしたい場合。
「NULL = NULL」では「真」にならないという障壁がある。

つまり、以下のような感じになり、「ギ」の部分が「真」でないという誤算がある。

【一致比較の場合】    【不一致比較の場合】
┌─┬─┬─┬─┐    ┌─┬─┬─┬─┐
│  │a│b│ヌ│    │  │a│b│ヌ│
├─┼─┼─┼─┤    ├─┼─┼─┼─┤
│a│真│偽│偽│    │a│偽│真│ギ│
├─┼─┼─┼─┤    ├─┼─┼─┼─┤
│b│偽│真│偽│    │b│真│偽│ギ│
├─┼─┼─┼─┤    ├─┼─┼─┼─┤
│ヌ│偽│偽│ギ│    │ヌ│ギ│ギ│偽│
└─┴─┴─┴─┘    └─┴─┴─┴─┘

ということで、「ギ」を「真」にするSQL文は以下のようになる。

【一致比較の場合】
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM [表1]                                                              │
│        FULL JOIN [表2]                                                     │
│          ON [表1].[キー] = [表2].[キー]                                    │
│    WHERE [表1].[列] = [表2].[列]                                           │
│       OR (([表1].[列] IS NULL) AND ([表2].[列] IS NULL));                  │
└──────────────────────────────────────┘

【不一致比較の場合】
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM [表1]                                                              │
│        FULL JOIN [表2]                                                     │
│          ON [表1].[キー] = [表2].[キー]                                    │
│    WHERE [表1].[列] <> [表2].[列]                                          │
│       OR (([表1].[列] IS     NULL) AND ([表2].[列] IS NOT NULL))           │
│       OR (([表1].[列] IS NOT NULL) AND ([表2].[列] IS     NULL));          │
└──────────────────────────────────────┘

もっと簡単な方法がありそうな気もするが、原始的な方法であれば上記の通りとなる。
分類:SQL
DB設計/削除済フラグと復活の考察
2014年10月22日
削除処理時、直接DELETEで抹消するのではなく、
削除済フラグを立ててで削除レコード扱いとしたとする。

この場合、自然キーとサロゲートキー(主キー)のあるレコードで
同一自然キーで再度追加したら、以下の二つの対応ができる。

(1) 削除レコードの削除済フラグを落として、上書きする(復活)
(2) 別サロゲートキーを採番して別レコードとして追加する(追加)

容量的なことを考えると前者が効率的だし、履歴管理的なことを考えると後者が実用的。

では、そのレコードに子分がいた場合には?

前者は子分も復活できるが削除した経緯を知らない人が追加したつもりで
子分が突然ゾンビのように現れてくるということがおきる。

一方後者は、親分が一度削除されたら子分も削除される。復活はできない。
CASCADEのDELETEと同じようなものだ。

どっちらかというと後者が一般的か。
間違って削除したのを復活するのは
ハードディスクから削除データを復活する的な職人技と考えれば、
前者はSQLで解決できるが、一般的には簡単にできないという点で合致する。
分類:SQL
データベース/削除済みフラグと一意性制約
2014年10月20日
削除レコードを直接DELETEしたくない場合には、削除済みフラグなんかを設ける。
この時問題となるのが、自然キーの一意性制約を邪魔することだ。

例えば、会員№が自然キーでそれが「1」のレコードを削除した場合、
居座ってしまうので、再び会員№「1」のレコードを追加することはできない。

それじゃ、自然キーと削除済みフラグをまとめて一意性制約にするとする。
この場合、二回目以降の削除をすると、削除レコードが重複するので、
削除ができなくなる。

ということで、削除レコードは制約のない履歴テーブルへ移して…と考える訳だが
それをしなくても解決する方法がある。

(1) 部分インデックス(MSSQLやPostgreSQLの場合)
  条件に該当する中で一意性制約をつけるということができる。
  MSSQLではこんな感じ。
┌──────────────────────────────────────┐
│CREATE UNIQUE NONCLUSTERED INDEX [一意性制約]                               │
│    ON [dbo].[表] (                                                         │
│        [自然キー]          ASC                                             │
│    )                                                                       │
│    WHERE ([削除済フラグ] = 0);                                             │
└──────────────────────────────────────┘
  削除レコード(削除済フラグ=1)については、一意性制約が効かないので
  ちょうど、別履歴テーブルに移動したのと同じような感じになる。

(2) 一意性制約中のNULL特性(MySQLやOracleの場合)
  複合キーにNULLが混じっていると、一意性制約の範疇外となる特性を利用する。
  つまり制約を「自然キー+削除済みフラグ」にして、
  削除済みの場合は「TRUE」ではなく「NULL」としてしまうのだ。
  「自然キー+NULL」となれば一意性制約が効かないので、
  「自然キー」の部分が重複していてもいけてしまうというわけだ。
分類:SQL
SQL/一意性制約とNULL
2014年10月12日
主キー(PRIMARY KEY)制約は、非ヌル(NOT NULL)制約と一意性(UNIQUE)制約を
組み合わせたもので、普段はこれを使っているかあまり意識しないかもしれないが
一意性制約のみの場合、NULLの扱いはどうなるのか?という話。

実はRDBMSにより違ってくる

(1) NULLは一意性制約の対象外とみなす方式(MySQL、PostgreSQLなど)
→NULL以外が重複しなければNULLはいくらでも重複できる

(2) NULLも一意性制約の対象内とみなす方式(MSSQLなど)
→NULLは認めるが、一つしか認めない(複数あれば重複とみなす)

NULLはNULLと一致しない(「= NULL」ではなく「IS NULL」で判定)ものの
重複という点では見解が異なるようだ

ちなみに(1)で複合キーの場合、NULLが含まれていれば全体的にNULLとみなされるので
重複が可能となる点にも注意。(例えば「1,NULL」と「1,NULL」は重複できる)
分類:SQL
SQL/二階層以上先のLEFT JOIN
2014年08月25日
あまりないかもしれないが、直上にはないけど、そのまた上にある列と
「LEFT JOIN」したい場合、普通に以下のように書いたらNGだ。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│   FROM 親                                                                  │
│       LEFT 子                                                              │
│         ON 子.列A = 親.列A                                                 │
│           LEFT 孫                                                          │
│             ON  孫.列B = 親.列B                  ←×                      │
│             AND 孫.列C = 子.列C;                                           │
└──────────────────────────────────────┘

こんな時は、一旦上の階層でテーブルを完結させて、列が揃った時点で
そこに「LEFT JOIN」すればよい。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│   FROM (SELECT *                                                           │
│             FROM 親                                                        │
│                 LEFT 子                                                    │
│                   ON 子.列A = 親.列A) AS 親たち                            │
│       LEFT 孫                                                              │
│         ON  孫.列B = 親たち.列B                  ←○                      │
│         AND 孫.列C = 親たち.列C;                                           │
└──────────────────────────────────────┘
VIEWとかを駆使すれば見やすくなる。

ちなみに結合するキーの関係を図示すると以下のような変化が起こったってことだ。
┌─────┐  ┌─────┐
│親  子  孫│→│親たち  孫│
│●=●  ○│  │●      ○│
│●  ○  ●│  │●===●│
│○  ●=●│  │●===●│
└─────┘  └─────┘
分類:SQL
SQL/条件付き追加・削除
2014年03月31日
「OR REPLACE」   「REPLACE」…存在したら置き換える
「IF NOT EXISTS」「IGONRE」 …存在したら作らない
「IF EXISTS」               …存在しなかったら消さない
┌───────────────┬─────┬─────┐
│                              │  MySQL   │PostgreSQL│
├───────────────┼─────┼─────┤
│CREATE DATABASE               │    ○    │    ○    │
│CREATE OR REPLACE DATABASE    │    ×    │    ×    │
│CREATE DATABASE IF NOT EXISTS │    ○    │    ×    │
│───────────────│─────│─────│
│DROP DATABASE                 │    ○    │    ○    │
│DROP DATABASE IF EXISTS       │    ○    │    ×    │
├───────────────┼─────┼─────┤
│CREATE TABLE                  │    ○    │    ○    │
│CREATE OR REPLACE TABLE       │    ×    │    ×    │
│CREATE TABLE IF NOT EXISTS    │    ○    │    ×    │
│───────────────│─────│─────│
│DROP TABLE                    │    ○    │    ○    │
│DROP TABLE IF EXISTS          │    ○    │    ×    │
├───────────────┼─────┼─────┤
│CREATE INDEX                  │    ○    │    ○    │
│CREATE OR REPLACE INDEX       │    ×    │    ×    │
│CREATE INDEX IF NOT EXISTS    │    ×    │    ×    │
│───────────────│─────│─────│
│DROP INDEX                    │    ○    │    ○    │
│DROP INDEX IF EXISTS          │    ×    │    ×    │
├───────────────┼─────┼─────┤
│CREATE VIEW                   │    ○    │    ○    │
│CREATE OR REPLACE VIEW        │    ○    │    ○    │
│CREATE VIEW IF NOT EXISTS     │    ×    │    ×    │
│───────────────│─────│─────│
│DROP VIEW                     │    ○    │    ○    │
│DROP VIEW IF EXISTS           │    ○    │    ×    │
├───────────────┼─────┼─────┤
│CREATE TRIGGER                │    ○    │    ○    │
│CREATE OR REPLACE TRIGGER     │    ×    │    ×    │
│CREATE TRIGGER IF NOT EXISTS  │    ×    │    ×    │
│───────────────│─────│─────│
│DROP TRIGGER                  │    ○    │    ○    │
│DROP TRIGGER IF EXISTS        │    ○    │    ×    │
├───────────────┼─────┼─────┤
│INSERT                        │    ○    │    ○    │
│REPLACE                       │    ○    │    ×    │
│INSERT IGNORE                 │    ○    │    ×    │
│───────────────│─────│─────│
│DELETE                        │    ○    │    ○    │
└───────────────┴─────┴─────┘
分類:SQL、PostgreSQL、MySQL
SQL/途中で並べ替えても保証はされませんよ
2013年05月16日
ソートキーが二つ以上ある場合、優先度の低い順にソートしていけば、
並び替えができる(Excelなんかで試してみればいい)。
  ┌─┐                    ┌─┐                    ┌─┐
  │B2│                    │A1│                    │A1│
  │A1│─ 二列目でソート →│B1│─ 一列目でソート →│A2│
  │B1│                    │B2│                    │B1│
  │A2│                    │A2│                    │B2│
  └─┘                    └─┘                    └─┘

ということで、以下のような並び替えを…
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM 表                                                                 │
│    ORDER BY 列1 ASC,                                                       │
│             列2 ASC;                                                       │
└──────────────────────────────────────┘
以下のように副問い合わせで代用できるような気がする。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM (SELECT *                                                          │
│              FROM 表                                                       │
│              ORDER BY 列2 ASC                                              │
│          ) AS 別表                                                         │
│    ORDER BY 列1 ASC;                                                       │
└──────────────────────────────────────┘

でも、これは保証されない。
字面上は想定通りの処理順で記述したつもりでも、
オプティマイザっていうSQLを解析する機能が、処理順を適切に調整してしまうのだ。

ということで、ご注意を。
分類:SQL
前へ 1 2 3 4 5 6 次へ