MW211 EXIT

devlog
MSSQL/ジャーナル
2018年10月30日
┌──────────────────────────────────────┐
│CREATE TABLE [DB].[dbo].[T_表] (                                            │
│    [キー]          [int]               NOT NULL,                           │
│    [値]            [nvarchar](256)     NULL,                               │
│    [更新者]        [nvarchar](32)      NOT NULL,                           │
│    [更新日時]      [datetime]          NOT NULL    DEFAULT (GETDATE()),    │
│    CONSTRAINT [PK_表] PRIMARY KEY CLUSTERED (                              │
│        [キー]                  ASC                                         │
│    )                                                                       │
│);                                                                          │
└──────────────────────────────────────┘
例えば上記テーブルのジャーナルテーブル(更新履歴テーブル)を実装する方法。
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
【1】ジャーナルテーブルを作る
┌──────────────────────────────────────┐
│CREATE TABLE [DB].[dbo].[T_ジャーナル_表] (                                 │
│    [ジャーナルID]      [int] IDENTITY(1,1) NOT NULL,                   --※│
│    [ジャーナル区分]    [nchar](2)          NOT NULL,                   --※│
│    [キー]              [int]               NULL,                           │
│    [値]                [nvarchar](256)     NULL,                           │
│    [更新者]            [nvarchar](32)      NULL,                           │
│    [更新日時]          [datetime]          NULL,                           │
│    CONSTRAINT [PK_ジャーナル_表] PRIMARY KEY CLUSTERED (                   │
│        [ジャーナルID]          ASC                                     --※│
│    )                                                                       │
│);                                                                          │
└──────────────────────────────────────┘
  対象テーブルの各列について、制約を一切はずして、継承する。
  また、代わりに主キーとして連番([ジャーナルID])をあてる。
  それと、「追加」か「削除」を記録する区分([ジャーナル区分])も設置。
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
【2】トリガを仕込む
┌──────────────────────────────────────┐
│CREATE TRIGGER [dbo].[TRIGGER_ジャーナル_表] ON [DB].[dbo].[T_表]           │
│    AFTER INSERT, UPDATE, DELETE                                            │
│AS                                                                          │
│BEGIN                                                                       │
│    INSERT INTO [DB].[dbo].[T_ジャーナル_表] (                              │
│            [ジャーナル区分],                                               │
│            [キー],                                                         │
│            [値],                                                           │
│            [更新者],                                                       │
│            [更新日時]                                                      │
│        )                                                                   │
│        SELECT '削除' AS [ジャーナル区分],                                  │
│               [キー],                                                      │
│               [値],                                                        │
│               [更新者],                                                    │
│               [更新日時]                                                   │
│            FROM deleted;                                                   │
│    INSERT INTO [DB].[dbo].[T_ジャーナル_表] (                              │
│            [ジャーナル区分],                                               │
│            [キー],                                                         │
│            [値],                                                           │
│            [更新者],                                                       │
│            [更新日時]                                                      │
│        )                                                                   │
│        SELECT '追加' AS [ジャーナル区分],                                  │
│               [キー],                                                      │
│               [値],                                                        │
│               [更新者],                                                    │
│               [更新日時]                                                   │
│            FROM inserted;                                                  │
│END;                                                                        │
└──────────────────────────────────────┘
  MSSQLの場合は、「deleted」で更新前(削除前)のレコードが、
  「inserted」で更新後(追加後)のレコードが取得できるので
  それをそのままジャーナルにしてしまった方が間違いないようだ。

  もちろん、INSERT・UPDATE・DELETEに分けるという方法もあるが
  一つのトリガ内で、これを(何をトリガとしたのかを)識別することは難しい模様。
  そうなると、トリガを三つ用意した方が間違いないようではあるが。。。
分類:MSSQL
MSSQL/bit型とExcel出力
2018年08月04日
MSSQLにおけるbool型相当はbit型であるが、
SQL文中では「TRUE/FALSE」ではなく「1/0」で扱う。
よって、int型と同じなのかなと思うと当然ながら違うこともある。

その一つがExcelにおける文字列型のセルに出力した際に
「TRUE/FALSE」と表示される点だ。
なお、「TRUE」や「FALSE」といった文字列ではない点に注意。
分類:MSSQL
MSSQL/Key-Valueチェーン
2018年08月03日
Key-Value形式のテーブルで、Valueに他のKeyがある場合
それを繋げて最終的なValueを取得するSQL文。
なお、循環(無限ループ)の場合は、最初の階層の結果を返却する。
┌──────────────────────────────────────┐
│WITH [起点] (                                                               │
│        [キー],                                                             │
│        [バリュー]                                                          │
│    ) AS (                                                                  │
│        SELECT [キー],                                                      │
│               [バリュー]                                                   │
│            FROM 表 [表]                                                    │
│            WHERE [キー] = 値                                               │
│    ),                                                                      │
│    [再帰] (                                                                │
│        [キー],                                                             │
│        [階層],                                                             │
│        [直前キー],                                                         │
│        [バリュー],                                                         │
│        [循環]                                                              │
│    ) AS (                                                                  │
│        SELECT [キー],                                                      │
│               1                 AS [階層],                                 │
│               [キー]            AS [直前キー],                             │
│               [バリュー],                                                  │
│               0                 AS [循環]                                  │
│            FROM [起点]                                                     │
│        UNION ALL                                                           │
│        SELECT [再帰].[キー],                                               │
│               [再帰].[階層] + 1 AS [階層],                                 │
│               [表].[キー]       AS [直前キー],                             │
│               [表].[バリュー],                                             │
│               CASE                                                         │
│                 WHEN [再帰].[キー] = [表].[バリュー]                       │
│                   OR [再帰].[階層] > 99              THEN 1                │
│                 ELSE                                      0                │
│               END AS [循環]                                                │
│            FROM [再帰]                                                     │
│                INNER JOIN 表 AS [表]                                       │
│                  ON [表].[キー] = [再帰].[バリュー]                        │
│            WHERE [再帰].[循環] = 0                                         │
│    )                                                                       │
│SELECT [キー],                                                              │
│       [階層],                                                              │
│       [直前キー],                                                          │
│       [バリュー]                                                           │
│    FROM [再帰]                                                             │
│    WHERE [循環] = 0                                                        │
│      AND NOT EXISTS (                                                      │
│              SELECT *                                                      │
│                  FROM [再帰] AS [他]                                       │
│                  WHERE [他].[階層] > [再帰].[階層]                         │
│          )                                                                 │
│UNION ALL                                                                   │
│SELECT [キー],                                                              │
│       NULL       AS [階層],                                                │
│       NULL       AS [直前キー],                                            │
│       [バリュー]                                                           │
│    FROM [起点]                                                             │
│    WHERE EXISTS (                                                          │
│              SELECT *                                                      │
│                  FROM [再帰]                                               │
│                  WHERE [循環] = 1                                          │
│          )                                                                 │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/MERGE文を片方だけ
2018年07月30日
UPSERT的な以下MERGE文、WHEN句は削ることができる。
(でも一つは残さないとエラーだけど)
┌──────────────────────────────────────┐
│MERGE INTO [出力D]                                                         │
│    USING [入力D]                                                          │
│      ON [入力D].[キー] = [出力D].[キー]                                  │
│    WHEN MATCHED THEN                                                       │
│        UPDATE SET [列] = [入力D].[列]                                     │
│    WHEN NOT MATCHED BY TARGET THEN                                         │
│        INSERT ([列]) VALUES ([入力D].[列])                                │
│;                                                                           │
└──────────────────────────────────────┘

以下だとINSERT同等。(重複していたらINSERTと違ってエラーにはならない)
┌──────────────────────────────────────┐
│MERGE INTO [出力D]                                                         │
│    USING [入力D]                                                          │
│      ON [入力D].[キー] = [出力D].[キー]                                  │
│----WHEN MATCHED THEN                                                       │
│----    UPDATE SET [列] = [入力D].[列]                                     │
│    WHEN NOT MATCHED BY TARGET THEN                                         │
│        INSERT ([列]) VALUES ([入力D].[列])                                │
│;                                                                           │
└──────────────────────────────────────┘

以下だとUPDATE同等。(該当がなかったらUPDATE同様無視)
┌──────────────────────────────────────┐
│MERGE INTO [出力D]                                                         │
│    USING [入力D]                                                          │
│      ON [入力D].[キー] = [出力D].[キー]                                  │
│    WHEN MATCHED THEN                                                       │
│        UPDATE SET [列] = [入力D].[列]                                     │
│----WHEN NOT MATCHED BY TARGET THEN                                         │
│----    INSERT ([列]) VALUES ([入力D].[列])                                │
│;                                                                           │
└──────────────────────────────────────┘

ちなみに「WHEN MATCHED THEN」は、「WHEN MATCHED THEN DELETE」(DELETE文)もできる。

なお、いずれも「THEN NEXT SENTENSE」的な空処理はできないようだ。
つまりWHEN句は上記のようにコメントアウトするか文を削除する他ない。

一つ以上WHEN句が必要だけどそれを空処理にすることはできない、
ということになるが、そうなるとまったく意味不明なので
そんなことできなくてよいのかもしれない。
分類:MSSQL
MSSQL/ストアド関数と動的可変テーブル
2018年03月02日
ストアド関数で戻り値を可変のテーブル型とし、
関数内で動的にSQL文を生成した結果を戻り値として返すことはできるのか?

・ストアド関数で戻り値を可変のテーブル型とする場合には、
  処理を書くことができず(つまり動的にSQL文を書けない)、
  RETURN処理に固定のSELECT文を書けるのみ
  RETURN処理では、ストアドプロシージャを呼び出すこともできない

よって、無理のようだ
分類:MSSQL
MSSQL/マトリクス出力(pivot利用版)
2018年02月08日
┌──────────────────────────────────────┐
│GO                                                                          │
│    DECLARE @sql    nvarchar(max);                                          │
│    DECLARE @sql0   nvarchar(max);                                          │
│    DECLARE @sql1   nvarchar(max);                                          │
│    DECLARE @sql1a  nvarchar(max);                                          │
│    DECLARE @sql1b  nvarchar(max);                                          │
│    -- ---------------------------------------------------------------------│
│    --   見出                                                               │
│    -- ---------------------------------------------------------------------│
│    SELECT @sql0 = ISNULL(@sql0 + ',','')                                   │
│                 + '(SELECT [列名]'                                         │
│                 + '     FROM [列M]'                                       │
│                 + '     WHERE [列ID] = ' + CONVERT(varchar,[列ID])         │
│                 + ') AS [' + CONVERT(varchar,[列ID]) + ']'                 │
│        FROM [列M]                                                         │
│        ORDER BY [列順];                                                    │
│    SET @sql0 = 'SELECT 0    AS [行順],'                                    │
│              + '       NULL AS [行ID],'                                    │
│              + @sql0;                                                      │
│    -- ---------------------------------------------------------------------│
│    --   明細                                                               │
│    -- ---------------------------------------------------------------------│
│    SELECT @sql1a = ISNULL(@sql1a + ',','')                                 │
│                  + '[' + CONVERT(varchar,[列ID]) + ']',                    │
│           @sql1b = ISNULL(@sql1b + ',','')                                 │
│                  + '[ピボット].[' + CONVERT(varchar,[列ID]) + ']'          │
│        FROM [列M]                                                         │
│        ORDER BY [列順];                                                    │
│    SET @sql1 = 'SELECT [行M].[行順],'                                     │
│              + '       [ピボット].[行ID],'                                 │
│              + @sql1b                                                      │
│              + '    FROM ('                                                │
│              + '        SELECT [列M].[列ID],'                             │
│              + '               [行M].[行ID],'                             │
│              + '               [行列D].[データ]'                          │
│              + '            FROM [列M]'                                   │
│              + '                CROSS JOIN [行M]'                         │
│              + '                LEFT JOIN [行列D]'                        │
│              + '                  ON  [行列D].[列ID] = [列M].[列ID]'     │
│              + '                  AND [行列D].[行ID] = [行M].[行ID]'     │
│              + '    ) AS [行列M]'                                         │
│              + '    PIVOT ('                                               │
│              + '        MAX([データ]) FOR [列ID] IN (' + @sql1a + ')'      │
│              + '    ) AS [ピボット]'                                       │
│              + '        INNER JOIN [行M]'                                 │
│              + '          AND [行M].[行ID] = [ピボット].[行ID]';          │
│    -- ---------------------------------------------------------------------│
│    --   統合                                                               │
│    -- ---------------------------------------------------------------------│
│    SET @sql = 'SELECT *'                                                   │
│             + '    FROM (' + @sql0 + ' UNION ALL ' + @sql1 + ') AS [行列]' │
│             + '    ORDER BY [行順] ASC;';                                  │
│    EXECUTE (@sql);                                                         │
│GO                                                                          │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/マトリクス出力
2018年02月07日
┌──────────────────────────────────────┐
│GO                                                                          │
│    DECLARE @sql    [nvarchar](max);                                        │
│    DECLARE @sql0   [nvarchar](max);                                        │
│    DECLARE @sql1   [nvarchar](max);                                        │
│    -- ---------------------------------------------------------------------│
│    --   見出                                                               │
│    -- ---------------------------------------------------------------------│
│    SELECT @sql0 = ISNULL(@sql0 + ',','')                                   │
│                 + '(SELECT [列名]'                                         │
│                 + '     FROM [列M]'                                       │
│                 + '     WHERE [列ID] = ' + CONVERT([varchar], [列ID])      │
│                 + ') AS [' + CONVERT([varchar], [列ID]) + ']'              │
│        FROM [列M]                                                         │
│        ORDER BY [列順];                                                    │
│    SET @sql0 = 'SELECT 0    AS [行順],'                                    │
│              + '       NULL AS [行ID],'                                    │
│              + @sql0;                                                      │
│    -- ---------------------------------------------------------------------│
│    --   明細                                                               │
│    -- ---------------------------------------------------------------------│
│    SELECT @sql1 = ISNULL(@sql1 + ',','')                                   │
│                 + '(SELECT [行列D].[データ]'                              │
│                 + '     FROM [行列D]'                                     │
│                 + '     WHERE [行列D].[列ID] = '                          │
│                                                + CONVERT([varchar], [列ID])│
│                 + '       AND [行列D].[行ID] = [行M].[行ID]'             │
│                 + ') AS [' + CONVERT([varchar], [列ID]) + ']'              │
│        FROM [列M]                                                         │
│        ORDER BY [列順];                                                    │
│    SET @sql1 = 'SELECT [行M].[行順],'                                     │
│              + '       [行M].[行ID],'                                     │
│              + @sql1                                                       │
│              + '    FROM [行M]';                                          │
│    -- ---------------------------------------------------------------------│
│    --   統合                                                               │
│    -- ---------------------------------------------------------------------│
│    SET @sql = 'SELECT *'                                                   │
│             + '    FROM (' + @sql0 + ' UNION ALL ' + @sql1 + ') AS [行列]' │
│             + '    ORDER BY [行順] ASC;';                                  │
│    EXECUTE (@sql);                                                         │
│GO;                                                                         │
└──────────────────────────────────────┘

なお、[列ID]が文字列の場合は以下に変更。
┌──────────────────────────────────────┐
│                 + '     WHERE [行列D].[列ID] = '                          │
│                                                + CONVERT([varchar], [列ID])│
└──────────────────────────────────────┘
  ↓
┌──────────────────────────────────────┐
│                 + '     WHERE [行列D].[列ID]                              │
│                                          = ' + CHAR(39) + [列ID] + CHAR(39)│
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/自動採番に0を入力
2017年05月10日
┌──────────────────────────────────────┐
│CREATE TABLE [表] (                                                         │
│    [連番]              [int] IDENTITY(1,1) NOT NULL,                       │
│    CONSTRAINT [PK_表] PRIMARY KEY CLUSTERED (                              │
│        [連番]              ASC                                             │
│    )                                                                       │
│);                                                                          │
└──────────────────────────────────────┘
上記のような、主キーが自動採番のレコードに、
後から「0」のレコードを挿入する方法。

以下のように、特殊な挿入を許可した上で行えばよい。もちろん終わったら元に戻す。
┌──────────────────────────────────────┐
│SET IDENTITY_INSERT [表] ON;                                                │
│INSERT INTO [表] ([連番]) VALUES (0);                                       │
│SET IDENTITY_INSERT [表] OFF;                                               │
└──────────────────────────────────────┘
ちなみに、その後に挿入した場合、「0」の次の「1」から
始まったりはしない(いつものように最大値の次の値から始まる)のでご安心を。
分類:MSSQL
ExcelVBA/MSSQL小数のプレースホルダ
2017年01月17日
┌──────────────────────────────────────┐
│CREATE PROCEDURE [dbo].[PROCEDURE_小数]                                     │
│    @引数小数               [decimal](8, 2)                                 │
└──────────────────────────────────────┘
MSSQLのストアドプロシージャの引数をdecimal型の小数で定義した場合
ExcelVBAのプレースホルダ的には、以下のような形式で値を指定してあげる。
┌──────────────────────────────────────┐
│Dim SQLコマンド As New ADODB.Command                                        │
│With SQLコマンド                                                            │
│    .ActiveConnection = mデータベース                                       │
│    .CommandType = adCmdStoredProc                                          │
│    .CommandText = "PROCEDURE_小数"                                         │
│    .NamedParameters = True                                                 │
│    .Parameters.Append .CreateParameter("@引数小数", adDecimal, adParamInput)
│    With .Parameters("@引数小数")                                           │
│        .Precision = 8                                                      │
│        .NumericScale = 2                                                   │
│    End With                                                                │
│    .Execute                                                                │
└──────────────────────────────────────┘
分類:ExcelVBA、MSSQL
MSSQL/レコードなしを返却
2015年08月31日
ストアドプロシージャでレコードを返すことになっているものの
条件分岐であきらかにレコードを返すものがない(0件レコードを返す)という時に
ダミーで0件レコードを返却したいが、適切な方法というのは見当たらない。

ということで、いくつか候補を考えてみた。
┌──────────────────────────────────────┐
│SELECT 1 WHERE 1 <> 1;                                                      │
├──────────────────────────────────────┤
│SELECT 0 WHERE 0 <> 0;                                                      │
├──────────────────────────────────────┤
│SELECT NULL WHERE NULL IS NOT NULL;                                         │
└──────────────────────────────────────┘
上に行くほど直感的、下に行くほど論理的ていう並びにしてみた。

とりあえず一番下のを推奨としたい。
分類:MSSQL
前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 次へ