MW211 EXIT

devlog
SQL/FULL JOINの並列と直列
2023年03月29日
┌──┬───────────────────────────────────┐
│並列│SELECT COUNT(*)                                                       │
│    │    FROM 表1                                                          │
│    │        FULL JOIN 表2                                                 │
│    │          ON 表2.キー = 表1.キー                                      │
│    │        FULL JOIN 表3                                                 │
│    │          ON 表3.キー = 表1.キー                                      │
├──┼───────────────────────────────────┤
│直列│SELECT COUNT(*)                                                       │
│    │    FROM 表1                                                          │
│    │        FULL JOIN 表2                                                 │
│    │            FULL JOIN 表3                                             │
│    │              ON 表3.キー = 表2.キー                                  │
│    │          ON 表2.キー = 表1.キー                                      │
└──┴───────────────────────────────────┘
FULL JOINで2つ以上の表を上記のように、
並列につないだ場合と直列につないだ場合の違いについて。

以下のように違ってくる。
┌──┬───────────────────────────────────┐
│並列│WITH [表1] AS (                                                       │
│    │         SELECT *                                                     │
│    │             FROM (                                                   │
│    │                 VALUES (1, 'A'),                                     │
│    │                        (2, 'B')                                      │
│    │             ) AS [表]([キー], [値])                                  │
│    │     ),                                                               │
│    │     [表2] AS (                                                       │
│    │         SELECT *                                                     │
│    │             FROM (                                                   │
│    │                 VALUES (3, 'C'),                                     │
│    │                        (4, 'D')                                      │
│    │             ) AS [表]([キー], [値])                                  │
│    │     ),                                                               │
│    │     [表3] AS (                                                       │
│    │         SELECT *                                                     │
│    │             FROM (                                                   │
│    │                 VALUES (1, 'E'),                                     │
│    │                        (2, 'F')                                      │
│    │             ) AS [表]([キー], [値])                                  │
│    │     )                                                                │
│    │SELECT *                                                              │
│    │    FROM [表1]                                                        │
│    │      FULL JOIN [表2]                                                 │
│    │        ON [表2].[キー] = [表1].[キー]                                │
│    │      FULL JOIN [表3]                                                 │
│    │        ON [表3].[キー] = [表1].[キー]                                │
│    │--→4件                                                               │
├──┼───────────────────────────────────┤
│直列│WITH [表1] AS (                                                       │
│    │         SELECT *                                                     │
│    │             FROM (                                                   │
│    │                 VALUES (1, 'A'),                                     │
│    │                        (2, 'B')                                      │
│    │             ) AS [表]([キー], [値])                                  │
│    │     ),                                                               │
│    │     [表2] AS (                                                       │
│    │         SELECT *                                                     │
│    │             FROM (                                                   │
│    │                 VALUES (3, 'C'),                                     │
│    │                        (4, 'D')                                      │
│    │             ) AS [表]([キー], [値])                                  │
│    │     ),                                                               │
│    │     [表3] AS (                                                       │
│    │         SELECT *                                                     │
│    │             FROM (                                                   │
│    │                 VALUES (1, 'E'),                                     │
│    │                        (2, 'F')                                      │
│    │             ) AS [表]([キー], [値])                                  │
│    │     )                                                                │
│    │SELECT *                                                              │
│    │    FROM [表1]                                                        │
│    │      FULL JOIN [表2]                                                 │
│    │          FULL JOIN [表3]                                             │
│    │            ON [表3].[キー] = [表2].[キー]                            │
│    │        ON [表2].[キー] = [表1].[キー]                                │
│    │--→6件                                                               │
└──┴───────────────────────────────────┘
分類:SQL
SQL/先入先出法の在庫シミュレーション
2020年06月20日
入庫レコードと出庫レコードを先入先出法で紐づける場合には
出庫側を両者の重複区間とすればよい。(例はMSSQL)
┌──────────────────────────────────────┐
│WITH [入庫D]([ID],[数]) AS (                                               │
│         SELECT * FROM (VALUES (1, 3),                                      │
│                               (2, 3),                                      │
│                               (3, 3)) AS [入庫D]([ID],[数])               │
│     ),                                                                     │
│     [出庫D]([ID],[数]) AS (                                               │
│         SELECT * FROM (VALUES (1, 1),                                      │
│                               (2, 4)) AS [出庫D]([ID],[数])               │
│     )                                                                      │
│SELECT [入庫D].[ID] AS [入庫ID],                                           │
│       [出庫D].[ID] AS [出庫ID],                                           │
│       CASE                                                                 │
│         WHEN [出庫D].[始] < [入庫D].[始] THEN [入庫D].[始]              │
│         ELSE                                    [出庫D].[始]              │
│       END AS [始],                                                         │
│       CASE                                                                 │
│         WHEN [出庫D].[終] > [入庫D].[終] THEN [入庫D].[終]              │
│         ELSE                                    [出庫D].[終]              │
│       END AS [終]                                                          │
│    FROM (                                                                  │
│        SELECT [ID],                                                        │
│               ISNULL((SELECT SUM([数])                                     │
│                           FROM [入庫D] AS [他D]                          │
│                           WHERE [他D].[ID] < [入庫D].[ID]),              │
│                      0) + 1 AS [始],                                       │
│               (SELECT SUM([数])                                            │
│                    FROM [入庫D] AS [他D]                                 │
│                    WHERE [他D].[ID] <= [入庫D].[ID]) AS [終]             │
│            FROM [入庫D]                                                   │
│    ) AS [入庫D]                                                           │
│        LEFT JOIN (                                                         │
│            SELECT [ID],                                                    │
│                   ISNULL((SELECT SUM([数])                                 │
│                               FROM [出庫D] AS [他D]                      │
│                               WHERE [他D].[ID] < [出庫D].[ID]),          │
│                          0) + 1 AS [始],                                   │
│                   (SELECT SUM([数])                                        │
│                        FROM [出庫D] AS [他D]                             │
│                        WHERE [他D].[ID] <= [出庫D].[ID]) AS [終]         │
│                FROM [出庫D]                                               │
│        ) AS [出庫D]                                                       │
│          ON  [出庫D].[始] <= [入庫D].[終]                                │
│          AND [出庫D].[終] >= [入庫D].[始]                                │
│    ORDER BY [入庫D].[ID] ASC,                                             │
│             [出庫D].[ID] ASC;                                             │
└──────────────────────────────────────┘
分類:SQL
SQL/孫との関わり
2018年12月23日
孫からのアクセスはエラーとなる。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM [親表]                                                             │
│        INNER JOIN [子表]                                                   │
│            INNER JOIN [孫表]                                               │
│              ON  [孫表].[孫ID] = [子表].[孫ID]                             │
│              AND [孫表].[列]   = [親表].[列]    -------------------------NG│
│          ON  [子表].[子ID] = [親表].[親ID]                                 │
└──────────────────────────────────────┘
孫へのアクセスはよい。
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM [親表]                                                             │
│        INNER JOIN [子表]                                                   │
│            INNER JOIN [孫表]                                               │
│              ON  [孫表].[孫ID] = [子表].[孫ID]                             │
│          ON  [子表].[子ID] = [親表].[親ID]                                 │
│          AND [孫表].[列]   = [親表].[列]        -------------------------OK│
└──────────────────────────────────────┘
分類:SQL
SQLite/SQLite2からSQLite3へのデータ変換
2018年10月28日
(1) SQLite3のコマンドラインツールを入手する
    以下のサイトから最新版を入手する
    https://www.sqlite.org/download.html
    例)「sqlite-tools-win32-x86-3250200.zip」

    →圧縮ファイルが入手でき、中に「sqlite3.exe」が入っている

(2) SQLite2のコマンドラインツールを入手する
    ダウンロードサイトはないようなので、直接URL入力する
    http://www.sqlite.org/sqlite-2_8_17.zip

    URL中のバージョン部分は適宜変更のこと

    変更履歴は以下で確認できる(SQLite2の最終版は現在「2.8.17」)
    https://www.sqlite.org/changes.html

    →圧縮ファイルが入手でき、中に「sqlite.exe」が入っている

(3) 「sqlite3.exe」と「sqlite.exe」を任意のフォルダに置き
    コマンドプロンプトにてそのフォルダへ移動する

(4) コマンドを実行
    ┌───────────────────────────────────┐
    │> sqlite sqlite2データ.db .dump | sqlite3 sqlite3データ.db            │
    └───────────────────────────────────┘
    SQLite2で(「.dump」にて全ての)ダンプデータを吐き出し、パイプを経由して
    それを元にSQLite3のデータファイルを新規作成する形になる

以上でSQLite3のデータへの変換は完了
分類:SQL
SQL/DEFAULT定義の誤解
2018年08月07日
SQL文のDEFAULT定義は、あくまで列が指定されなかった場合の既定値であり
NULLを代入した場合の代替値ではないことに注意。
○INSERT文にて列が指定されなかった場合には基本的にNULLが代入される
○この場合、DEFAULT定義があった場合にはその値が代入される
○UPDATE文にてNULLを代入しても、DEFAULT定義の値は無視される
×INSERT文にてNULLを代入したら、DEFAULT定義の値が代入される
  →NULLが代入される

よって、NOT NULL制約とDEFAULT定義が両方定義してある列について
DEFAULT定義があるから(NOT NULL制約にはひっかからなくて)安心というのは間違いだ。
分類:SQL
SQL/親子表と外部キーの関係
2018年07月05日
以下の関係になる。
┌ 子表 ────────┐┌ 親表 ──┐
│┌───┐┌────┐││┌───┐│
││主キー││外部キー├──┤主キー││
│└───┘└────┘││└───┘│
│                      │└─────┘
│                      │┌ 親表 ──┐
│          ┌────┐││┌───┐│
│          │外部キー├──┤主キー││
│          └────┘││└───┘│
└───────────┘└─────┘
分類:SQL
SQL/採番をバッティングさせない方法
2018年01月11日
①列の自動採番機能を使う
  ○確実(漏れがない、直接SQL文で更新しても効く)
  ×単一列でしか利用できない(複合キーには向かない)
②更新前トリガを使う
  ○確実(漏れがない、直接SQL文で更新しても効く)
  ○採番方法は自由(複合キーでもOK)
  △トリガの管理が煩雑(他列が増減した場合にトリガも追従させないといけない)
③排他トランザクションを使う
  ○採番方法は自由(複合キーでもOK)
  △不確実(処理ルートに漏れがあってはならない、直接SQL文で更新したら対応外)
④プログラムで行う
  ○採番方法は自由(複合キーでもOK)
  △不確実(処理ルートに漏れがあってはならない、直接SQL文で更新したら対応外)
  △管理が煩雑(SQLに一元化されない)
分類:SQL
SQL/更新元がMAX()だったら
2017年12月21日
素朴な疑問。
  ┌─┐                             ┌─────┐    ┌─────┐
  │ 1│                             │ 3+ 1= 4│    │ 3+ 1= 4│
  ├─┤                             ├─────┤    ├─────┤
  │ 2│を、MAX()+自身で更新したら  │ 3+ 2= 5│?  │ 4+ 2= 6│?
  ├─┤                             ├─────┤    ├─────┤
  │ 3│                             │ 3+ 3= 6│    │ 6+ 3= 9│
  └─┘                             └─────┘    └─────┘
都度都度MAX()結果が変わって雪だるま式に増えたりしないのだろうか?


やってみた(MSSQLで)。

まず、以下を準備。
┌──────────────────────────────────────┐
│CREATE TABLE [表] (                                                         │
│    [列] [int] NULL,                                                    ┌─┐
│);                                                                      │ 1│
├────────────────────────────────────├─┤
│INSERT INTO [表] VALUES (1);                                            │ 2│
│INSERT INTO [表] VALUES (2);                                            ├─┤
│INSERT INTO [表] VALUES (3);                                            │ 3│
└────────────────────────────────────└─┘

で、以下はエラー。
┌──────────────────────────────────────┐
│UPDATE [表]                                                                 │
│    SET [列] = MAX([列]) + [列];                                            │
├──────────────────────────────────────┤
│UPDATE [表]                                                                 │
│    SET [列] =  MAX([列])  + [列]                                           │
│    FROM [表];                                                              │
└──────────────────────────────────────┘
→「UPDATEステートメントのSETリストには集計を含めることはできません。」

以下はできた。
┌──────────────────────────────────────┐
│UPDATE [表]                                                                 │
│    SET [列] = (SELECT MAX([列]) FROM [表]) + [列];                         │
└──────────────────────────────────────┘
結果は…
┌─┐
│ 4│
├─┤
│ 5│
├─┤
│ 6│
└─┘
雪だるま式には増えないみたい。(期待した結果ではある)

あくまで、副問合せの結果が確定した上で、
主問合せ(UPDATE)が始まるって感じなのかな。
(最初のエラーのやつは本来は雪だるま式だったのかもしれない)
分類:SQL
SQL/優先順位台帳
2017年09月27日
優先順位を決めた優先順位台帳がある場合に、それを反映させる方法。
(干支を例とした優先順位台帳の場合)

優先順位順に並び替えるには、結合してあげればよい。
┌──────────────────────────────────────┐
│WITH 優先順位台帳 (                                                         │
│         順位,                                                              │
│         値                                                                 │
│     ) AS (                                                                 │
│          VALUES (1, '子'),                                                 │
│                 (2, '丑'),                                                 │
│                 (3, '寅')                                                  │
│     )                                                                      │
│SELECT 表.キー,                                                             │
│       優先順位台帳.順位,                                                   │
│       表.干支                                                              │
│    FROM 表                                                                 │
│        INNER JOIN 優先順位台帳                                             │
│          ON 優先順位台帳.値 = 表.干支                                      │
│    ORDER BY 表.キー           ASC,                                         │
│             優先順位台帳.順位 ASC;                                         │
└──────────────────────────────────────┘

グループ毎に最優先のものを洗い出すには、
一度結合して、最優先の順位を探して、さらに結合して
その最優先の順位の値をもってくる形になる。
┌──────────────────────────────────────┐
│WITH 優先順位台帳 (                                                         │
│         順位,                                                              │
│         値                                                                 │
│     ) AS (                                                                 │
│          VALUES (1, '子'),                                                 │
│                 (2, '丑'),                                                 │
│                 (3, '寅')                                                  │
│     )                                                                      │
│SELECT 別表.集合キー,                                                       │
│       優先順位台帳.値,                                                     │
│       優先順位台帳.順位 AS 干支                                            │
│    FROM (                                                                  │
│        SELECT 表.集合キー,                                                 │
│               MIN(優先順位台帳.順位) AS 順位                               │
│            FROM 表                                                         │
│                INNER JOIN 優先順位台帳                                     │
│                  ON 優先順位台帳.値 = 表.干支                              │
│            GROUP BY 表.集合キー                                            │
│    ) AS 別表                                                               │
│        INNER JOIN 優先順位台帳                                             │
│          ON 優先順位台帳.順位 = 別表.順位;                                 │
│    ORDER BY 表.キー ASC;                                                   │
└──────────────────────────────────────┘
これをCASE文にて(CASE文をネストさせて)以下のようにやってしまうこともできる。
┌──────────────────────────────────────┐
│SELECT 集合キー,                                                            │
│       CASE MIN(CASE 干支                                                   │
│                  WHEN '子' THEN 1                                          │
│                  WHEN '丑' THEN 2                                          │
│                  WHEN '寅' THEN 3                                          │
│                END)                                                        │
│         WHEN 1 THEN '子'                                                   │
│         WHEN 2 THEN '丑'                                                   │
│         WHEN 3 THEN '寅'                                                   │
│       END AS 干支                                                          │
│    FROM 表                                                                 │
│    WHERE 干支 IN ('子','丑','寅')                                          │
│    GROUP BY 集合キー                                                       │
│    ORDER BY 集合キー ASC;                                                  │
└──────────────────────────────────────┘
なお、いずれも想定外の値(優先順位台帳にない値)は無視する想定である。
分類:SQL
SQL/CASE文で更新したくない条件の場合
2017年09月26日
CASE文にて更新したくない条件の場合は、更新先の列を更新元にしてあげればよい。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET 列 = 列;                                                            │
└──────────────────────────────────────┘
イメージ的には上記のような感じすれば、更新されない。

例えば、条件が偽の場合にのみNULLを設定する時は以下のような感じになる。
┌──────────────────────────────────────┐
│UPDATE 表                                                                   │
│    SET 列 = CASE                                                           │
│               WHEN 条件 THEN 列                                            │
│               ELSE           NULL                                          │
│             END;                                                           │
└──────────────────────────────────────┘
なお、トリガは起動してしまうので、更新差分があったかどうかのチェックを
加えてあげる必要がある。
分類:SQL
前へ 1 2 3 4 5 6 次へ