MW211 EXIT

devlog
MSSQL/マッチング・後編
2014年12月15日
MERGE文はあきらめて、地道にINSERT・UPDATE文でやっちまうのが手っ取り早い。

「変更→削除→追加」の順が妥当なようだ。

ということで、以下のような感じで。
┌──────────────────────────────────────┐
│-- 変更                                                                     │
│UPDATE [旧表]                                                               │
│    SET [列]       = [新表].[列],                                           │
│        [更新日時] = getdate()                                              │
│    FROM [旧表]                                                             │
│        INNER JOIN [新表]                                                   │
│          ON  [新表].[キー] =  [旧表].[キー]                                │
│          AND [新表].[列]   <> [旧表].[列]                                  │
│    WHERE [旧表].[削除済フラグ] = 0;                                        │
├──────────────────────────────────────┤
│-- 削除                                                                     │
│UPDATE [旧表]                                                               │
│    SET [削除済フラグ] = 1,                                                 │
│        [更新日時]     = getdate()                                          │
│    WHERE [旧表].[削除済フラグ] = 0                                         │
│      AND NOT EXISTS (                                                      │
│              SELECT *                                                      │
│                  FROM [新表]                                               │
│                  WHERE [新表].[キー]         = [旧表].[キー]               │
│                    AND [新表].[削除済フラグ] = 0                           │
│          );                                                                │
├──────────────────────────────────────┤
│-- 追加                                                                     │
│INSERT INTO [旧表] (                                                        │
│        [キー],                                                             │
│        [列],                                                               │
│        [更新日時]                                                          │
│    )                                                                       │
│    SELECT [新表].[キー],                                                   │
│           [新表].[列],                                                     │
│           getdate()                                                        │
│        FROM [新表]                                                         │
│        WHERE [新表].[削除済フラグ] = 0                                     │
│          AND NOT EXISTS (                                                  │
│                  SELECT *                                                  │
│                      FROM [旧表] AS [追加先]                               │
│                      WHERE [追加先].[キー]         = [新表].[キー]         │
│                        AND [追加先].[削除済フラグ] = 0                     │
│              );                                                            │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/マッチング・前編
2014年12月14日
旧表に新表を突合させ、旧表がなければ追加、旧表があれば更新、
逆に新表になければ削除という典型的なマッチング処理がある。

これはMERGE文で一発できる。
┌──────────────────────────────────────┐
│MERGE INTO [旧表]                                                           │
│    USING [新表]                                                            │
│      ON  [旧表].キー = [新表].[キー]                                       │
│    WHEN MATCHED THEN                                                       │
│        UPDATE SET [列] = [新表].[列]                                       │
│    WHEN NOT MATCHED BY TARGET THEN                                         │
│        INSERT (                                                            │
│                [キー],                                                     │
│                [列]                                                        │
│            ) VALUES (                                                      │
│                [新表].[キー],                                              │
│                [新表].[列]                                                 │
│            )                                                               │
│    WHEN NOT MATCHED BY SOURCE THEN                                         │
│        DELETE;                                                             │
└──────────────────────────────────────┘
しかし、これに以下の条件が付いた場合、途端に対応できなくなる
  ・削除は直接DELETEするのではなく、削除済フラグを1にすることで行う
  ・変更の場合、更新する列に差分がある時のみ行う
    #同時に更新日時を更新することを想定(差分がない場合は更新したくない)

せいぜい対応できるのは、新表側を抽出することぐらいのみ。
┌──────────────────────────────────────┐
│MERGE INTO [旧表]                                                           │
│    USING (SELECT * FROM [新表] WHERE [削除済フラグ] = 0) AS [新表]         │
│      ON  [旧表].キー = [新表].[キー]                                       │
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
└──────────────────────────────────────┘

まず、旧表側(更新先)を抽出することはできない。
┌──────────────────────────────────────┐
│MERGE INTO (SELECT * FROM [旧表] WHERE [削除済フラグ] = 0) AS [旧表]        │
│    USING [新表]                                                            │
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
└──────────────────────────────────────┘

IF文を挟むこともできない。
┌──────────────────────────────────────┐
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
│    WHEN MATCHED THEN                                                       │
│        IF [列] <> [新表].[列]                                              │
│            UPDATE SET [列] = [新表].[列]                                   │
└──────────────────────────────────────┘

MERGE文は本格的なマッチング処理ではなく、
ミラーリング的なところに用いるものなのだろう。

ということで、その解決策は後編へ続く。。。
分類:MSSQL
MSSQL/ADODBで更新件数取得
2014年12月13日
ADODBで以下のような感じで、「.Execute」の第二引数で更新件数を取得できる。
┌──────────────────────────────────────┐
│Private データベース As New ADODB.Connection                                │
├──────────────────────────────────────┤
│データベース.Execute 更新SQL文, 更新件数                                    │
└──────────────────────────────────────┘
でも、トリガが設定されている場合、
トリガで作用したSQL文の結果が取得されてしまう。

これを抑止するのは、トリガの結果を戻さないようにする。
以下のような感じで冒頭で「SET NOCOUNT ON;」を実行して抑止すればよい。
┌──────────────────────────────────────┐
│CREATE TRIGGER [dbo].[トリガ] ON [DB].[dbo].[表]                            │
│    AFTER UPDATE                                                            │
│AS                                                                          │
│BEGIN                                                                       │
│    SET NOCOUNT ON;                                                         │
│    ~SQL文~                                                               │
│END;                                                                        │
└──────────────────────────────────────┘
もちろん、トリガの呼び元には抑止の影響がないので、
.Executeで実行したSQL文の更新件数が確実に取得できる。
分類:MSSQL
MSSQL/日付変換のストアドプロシージャ
2014年12月12日
日付変換関係のいろいろな処理を含んだストアドプロシージャは以下の通り。
┌──────────────────────────────────────┐
│CREATE PROCEDURE PROCEDURE_日付変換                                         │
│    @yyyymmdd char(8) = ''                                                  │
│AS                                                                          │
│BEGIN                                                                       │
│    DECLARE @return     int                                                 │
│    DECLARE @date       date                                                │
│    SET @return = 0                                                         │
│    IF @yyyymmdd = ''                                                       │
│        SET @yyyymmdd = CONVERT(NVARCHAR, GETDATE(), 112)                   │
│    BEGIN TRY                                                               │
│        SELECT @date = DATEFROMPARTS(substring(@yyyymmdd, 1, 4),            │
│                                     substring(@yyyymmdd, 5, 2),            │
│                                     substring(@yyyymmdd, 7, 2))            │
│    END TRY                                                                 │
│    BEGIN CATCH                                                             │
│        RETURN(-1)                                                          │
│    END CATCH                                                               │
│PRINT @date                                                                 │
│    RETURN(@return)                                                         │
│END;                                                                        │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/自動採番の取得
2014年12月08日
┌──────────────────────────────────────┐
│CREATE TABLE 表 (                                                           │
│    [キー]              [int] IDENTITY(1,1) NOT NULL,                       │
│    [列]                [int]               NULL,                           │
│    CONSTRAINT [主キー] PRIMARY KEY CLUSTERED (                             │
│        [キー]              ASC                                             │
│    )                                                                       │
│);                                                                          │
└──────────────────────────────────────┘
上記のような自動採番する表があって、
採番直後にその値を取得する方法には以下がある。
                                          ┌─────┬─────┬─────┐
                                          │セッション│ スコープ │ テーブル │
┌──┬─────────────────┼─────┼─────┼─────┤
│案1│SELECT MAX(キー) FROM 表;         │   全て   │   全て   │ 指定のみ │
├──┼─────────────────┼─────┼─────┼─────┤
│案2│SELECT IDENT_CURRENT('表');       │   全て   │   全て   │ 指定のみ │
├──┼─────────────────┼─────┼─────┼─────┤
│案3│SELECT @@IDENTITY;                │ 自身のみ │   全て   │   全て   │
├──┼─────────────────┼─────┼─────┼─────┤
│案4│SELECT SCOPE_IDENTITY();          │ 自身のみ │ 自身のみ │   全て   │
└──┴─────────────────┴─────┴─────┴─────┘
  セッションが「全て」のものは、同時に他から更新された場合、
  その影響を受けてしまう。
  スコープが「全て」の場合は、トリガなどにより連動した結果も反映されてしまう。
  よって、案4が一番安全なようだ。
分類:MSSQL
MSSQL/数値項目を文字列に変換する
2014年12月07日
【案1】キャストする
┌──────────────────────────────────────┐
│CAST([数値項目] AS varchar)                                                 │
└──────────────────────────────────────┘
  一番オーソドックスなやり方か。

【案2】型を変更する
┌──────────────────────────────────────┐
│CONVERT(varchar, [数値項目])                                                │
└──────────────────────────────────────┘
  これもオーソドックスなやり方か。

【案3】文字列に変更する
┌──────────────────────────────────────┐
│LTRIM(STR([数値項目]))                                                      │
└──────────────────────────────────────┘
  STR()で変換するのだが、左側に余計なスペースも入ってしまうので
  LTRIM()でこれを除去する。
分類:MSSQL
MSSQL/ユーザ関数の引数省略の罠
2014年12月03日
┌──────────────────────────────────────┐
│CREATE FUNCTION [dbo].[ユーザ関数] (@引数1 int,                             │
│                                    @引数2 int = 1)                         │
│:                                                                          │
└──────────────────────────────────────┘
上記(引数2)のように、引数を省略して既定値を活かす指定をした場合
「ユーザ関数(1)」でOKかと思いきやエラーとなる。
「ユーザ関数(1,DEFAULT)」と「DEFAULT」を明記してあげなければならないらしい。
分類:MSSQL
MSSQL/BULK INSERTによるCSV取込
2014年12月02日
一発でできる。すごい。
┌──────────────────┬───────────────────┐
│BULK INSERT [DB].[dbo].[表]         │                                      │
│    FROM 'ファイルフルパス'         │                                      │
│    WITH                            │                                      │
│    (                               │                                      │
│        FIELDTERMINATOR   = ',',    │区切り文字                            │
│        ROWTERMINATOR     = '\r\n', │改行文字                              │
│        FIRSTROW          = 2,      │明細開始行(ヘッダ行の有無)            │
│        LASTROW           = 0,      │明細終了行(フッタ行の有無) 0は末尾まで│
│        CHECK_CONSTRAINTS,          │制約をチェックする                    │
│        FIRE_TRIGGERS               │トリガを起動させる                    │
│    );                              │                                      │
└──────────────────┴───────────────────┘
分類:MSSQL
MSSQL/文字列照合
2014年11月30日
┌──────────────────────────────────────┐
│SELECT 列                                                                   │
│    FROM 表                                                                 │
│    WHERE 列 = '値';                                                        │
└──────────────────────────────────────┘
文字列で照合をかけると意外にゆるいことに気づく。

厳密に比較するには「COLLATE」をつける。
┌──────────────────────────────────────┐
│SELECT 列                                                                   │
│    FROM 表                                                                 │
│    WHERE 列 = '値' COLLATE JAPANESE_CS_AS_KS_WS;                           │
└──────────────────────────────────────┘

パラメータの意味は以下のような感じ。
┌─┬───────────────┬─┬──────────────────┐
│CS│大文字・小文字を区別          │CI│大文字・小文字を区別しない          │
├─┼───────────────┼─┼──────────────────┤
│AS│アクセント・濁音・破裂音を区別│AI│アクセント・濁音・破裂音を区別しない│
├─┼───────────────┼─┼──────────────────┤
│KS│ひらがな・カタカナを区別      │  │                                    │
├─┼───────────────┼─┼──────────────────┤
│WS│全角・半角を区別              │  │                                    │
└─┴───────────────┴─┴──────────────────┘
分類:MSSQL
MSSQL/sqlcmdでファイル出力
2014年11月28日
sqlcmdでSQL結果をファイル出力するには、以下のような感じで実行すればよい。
┌──────────────────────────────────────┐
│sqlcmd -S . -Q "SET NOCOUNT ON SELECT * FROM 表;" -h -1 -W -o "出力先.txt"  │
│                                                                  >> log.txt│
└──────────────────────────────────────┘

特にポイントとなるのが以下の点。
┌───────┬──────────────────────────────┐
│-h -1         │列名見出しの抑止                                            │
├───────┼──────────────────────────────┤
│SET NOCOUNT ON│「(x行処理されました))」の抑止                              │
├───────┼──────────────────────────────┤
│-W            │固定長右端余白の除去                                        │
└───────┴──────────────────────────────┘
余計な装飾は除去しておこう。
分類:MSSQL
前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 次へ