MW211 EXIT

devlog
MSSQL/文字列末尾のスペースと比較
2015年02月21日
┌─┬────────────────────────────────────┐
│真│'abc' = 'abc'                                                           │
├─┼────────────────────────────────────┤
│真│'abc' = 'abc '                                                          │
└─┴────────────────────────────────────┘
上記のような場合、後者は「偽」になりそうなものである。

しかしながら、これは(「真」になるのは)、
「ANSI/ISO SQL-92」の立派な規格なのである(比較では後続の空白は無視)。

ということで、データを管理・入力する時は、トリムを推奨しようねという話でした。

では、既に混入済みの場合は、どうやってみつけだすのか?

基本的にバイナリに変換して比較すれば、厳密に比較ができる。
┌─┬────────────────────────────────────┐
│真│CONVERT(binary, 'abc') = CONVERT(binary, 'abc')                         │
├─┼────────────────────────────────────┤
│偽│CONVERT(binary, 'abc') = CONVERT(binary, 'abc ')                        │
└─┴────────────────────────────────────┘

但し、型が違うと(特に「nvarchar」と「varchar」など)、
バイナリ変換される結果も変わってくるので、
念のため以下の様に事前に型を合わせておくというのも検討せねばならない。
┌─┬────────────────────────────────────┐
│真│CONVERT(binary, CONVERT(nvarchar(4000), 'abc'))                         │
│  │                       = CONVERT(binary, CONVERT(nvarchar(4000), 'abc'))│
├─┼────────────────────────────────────┤
│偽│CONVERT(binary, CONVERT(nvarchar(4000), 'abc'))                         │
│  │                      = CONVERT(binary, CONVERT(nvarchar(4000), 'abc '))│
└─┴────────────────────────────────────┘
変換を介するということは処理速度が遅くなので、必要なければ端折るのがよい。

また、以下の様な方法もある(「COLLATE JAPANESE_BIN =」ではないので注意)。
┌─┬────────────────────────────────────┐
│真│'abc' COLLATE JAPANESE_BIN LIKE 'abc'                                   │
├─┼────────────────────────────────────┤
│偽│'abc' COLLATE JAPANESE_BIN LIKE 'abc '                                  │
└─┴────────────────────────────────────┘
分類:MSSQL
MSSQL/疑似カレンダマスタ
2015年02月16日
2015/01/01以降から今日までの疑似カレンダマスタは
以下のような感じで作成できる。
┌──────────────────────────────────────┐
│SELECT CONVERT(nvarchar,                                                    │
│               DATEADD(DAY, generate_series, getdate()),                    │
│               111) AS [日付]                                               │
│    FROM generate_series(DATEDIFF(DAY,                                      │
│                                  getdate(),                                │
│                                  CONVERT(DATETIME, '2015-01-01')),         │
│                         0,                                                 │
│                         1);                                                │
└──────────────────────────────────────┘

なお、「generate_series()」は、PostgreSQLの関数でMSSQLには存在しないので
自前のユーザ関数で代替(別途参照)。
分類:MSSQL
MSSQL/generate_series()
2015年02月15日
PostgreSQLには、自動で連番テーブルを作成してくれる「generate_series()」という
便利な関数があるが、MSSQLにはない。

ということで、自前で作ると以下のような感じとなる。
┌──────────────────────────────────────┐
│CREATE FUNCTION [dbo].[generate_series] (                                   │
│    @引数開始               int,                                            │
│    @引数終了               int,                                            │
│    @引数増分               int = 1                                         │
│) RETURNS @結果 table (                                                     │
│    [generate_series]       int                                             │
│)                                                                           │
│AS                                                                          │
│BEGIN                                                                       │
│    DECLARE @値             int;                                            │
│    DECLARE @増分           int;                                            │
│    SET @値   = CASE                                                        │
│                  WHEN @引数開始 IS NULL THEN 1                             │
│                  ELSE                        @引数開始                     │
│                END;                                                        │
│    SET @増分 = CASE                                                        │
│                  WHEN @引数増分 IS NULL OR @引数増分 = 0 THEN 1            │
│                  ELSE                                         @引数増分    │
│                END;                                                        │
│    IF SIGN(@増分) =  1 AND @引数開始 > @引数終了                           │
│        RETURN;                                                             │
│    IF SIGN(@増分) = -1 AND @引数開始 < @引数終了                           │
│        RETURN;                                                             │
│    WHILE (1 = 1)                                                           │
│    BEGIN                                                                   │
│        INSERT INTO @結果([generate_series]) VALUES (@値);                  │
│        SET @値 = @値 + @増分;                                              │
│        IF SIGN(@増分) =  1 AND @値 > @引数終了                             │
│            BREAK;                                                          │
│        IF SIGN(@増分) = -1 AND @値 < @引数終了                             │
│            BREAK;                                                          │
│    END;                                                                    │
│    RETURN;                                                                 │
│END;                                                                        │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/横棒グラフ
2015年02月14日
┌──────────────────────────────────────┐
│SELECT [キー],                                                              │
│       [値],                                                                │
│       REPLICATE('■', [値]) AS [グラフ]                                    │
│    FROM [表];                                                              │
└──────────────────────────────────────┘
「REPLICATE()」は同じ文字を繰り返す。
分類:MSSQL
MSSQL/sysobjects.xtype
2015年02月10日
「sysobjects.xtype」(「SELECT xtype FROM sysobjects;」)の値は以下の通り。
┌─┬────────────────────────────────────┐
│U │テーブル(ユーザテーブル)                                                │
├─┼────────────────────────────────────┤
│V │ビュー                                                                  │
├─┼────────────────────────────────────┤
│P │ストアドプロシージャ                                                    │
│X │拡張ストアドプロシージャ                                                │
│RF│ストアドプロシージャ/レプリケーションフィルタ                          │
├─┼────────────────────────────────────┤
│FN│ストアドファンクション[スカラー型]                                      │
│TF│ストアドファンクション[テーブル型]                                      │
│IF│ストアドファンクション[インラインテーブル型]                            │
├─┼────────────────────────────────────┤
│TR│トリガ                                                                  │
├─┼────────────────────────────────────┤
│PK│主キー制約                                                              │
│UQ│一意制約                                                                │
│F │外部キー制約                                                            │
│C │チェック制約                                                            │
│D │既定値制約                                                              │
├─┼────────────────────────────────────┤
│S │システムテーブル                                                        │
│IT│内部テーブル                                                            │
│SQ│サービスキュー                                                          │
├─┼────────────────────────────────────┤
│PC│ストアドプロシージャ/アセンブリ(CLR)                                   │
│FS│ストアドファンクション[スカラー型]/アセンブリ(CLR)                     │
│FT│ストアドファンクション[テーブル型]/アセンブリ(CLR)                     │
│TA│トリガ/アセンブリ(CLR)                                                 │
│AF│集計関数(CLR)                                                           │
├─┼────────────────────────────────────┤
│L │ログ                                                                    │
│SN│シノニム                                                                │
│TT│テーブルの種類                                                          │
└─┴────────────────────────────────────┘
分類:MSSQL
MSSQL/日時変換
2015年02月09日
「datetime」型を変換する代表例。
┌──────────────────────────────────────┐
│CONVERT(nvarchar, [日時], 108) → hh:mm:ss                                  │
│CONVERT(nvarchar, [日時],  11) → yy/mm/dd                                  │
│CONVERT(nvarchar, [日時], 111) → yyyy/mm/dd                                │
│CONVERT(nvarchar, [日時],  12) → yymmdd                                    │
│CONVERT(nvarchar, [日時], 112) → yyyymmdd                                  │
└──────────────────────────────────────┘

例えば、日時で絞る場合、現在時刻より前で絞ると以下のようになる。
┌──────────────────────────────────────┐
│WHERE [日時] < getdate()                                                    │
└──────────────────────────────────────┘
当然ながら、現在時刻より前であれば本日分も抽出される。

これを前日以前で比較するには以下のような感じに互いに変換してしまえばよい。
┌──────────────────────────────────────┐
│WHERE CONVERT(nvarchar, [日時], 112) < CONVERT(nvarchar, getdate(), 112)    │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/エラーログにSQL発行状況を出力
2015年02月04日
SQLの発行状況をリアルタイムでエラーログに出力する方法。

まず、稼働中のインスタンス名を調べる。
「サービス」の「プロパティ」を参照すると
「サービス名」にインスタンス名が表示されている
→例えば「MSSQL$■」

次に、エラーログの位置を調べる。
例えば以下の辺り。
┌──────────────────────────────────────┐
│C:\Program Files\Microsoft SQL Server\MSSQL12.■\MSSQL\Log\ERRORLOG         │
└──────────────────────────────────────┘

準備が出来たら、調査開始。

MSSQLの以下のフラグをONに設定する。
・T3605=トレース結果をエラーログ出力
・T4032=コマンド(SQL文)をトレースする
「T3605」は設定済みなので「T4032」だけ設定し直す

コマンドプロンプト(管理者権限)で、以下の様に停止し再起動する。
┌──────────────────────────────────────┐
│>net stop MSSQL$■                                                          │
│SQL Server (■) サービスを停止中です.                                       │
│SQL Server (■) サービスは正常に停止されました。                            │
│                                                                            │
│>net start MSSQL$■ /T4032                                                  │
│SQL Server (■) サービスを開始します..                                      │
│SQL Server (■) サービスは正常に開始されました。                            │
└──────────────────────────────────────┘

次に「SQL Server Management Studio」以下のコマンドを実行する。
┌──────────────────────────────────────┐
│dbcc traceon(3605, -1)                                                      │
└──────────────────────────────────────┘

これで、ログにコマンド(SQL文)がエラーログにリアルタイムで出力される。

終了するには以下のコマンドを実行する。
┌──────────────────────────────────────┐
│dbcc traceoff(3605, -1)                                                     │
└──────────────────────────────────────┘
フラグも元に戻したい場合には、MSSQL再起動(サーバ再起動)など
分類:MSSQL
MSSQL/FROM句によるUPDATE文
2015年02月03日
  まず、「UPDATE」文による更新先(出力表)と、「FROM」句による更新元(入力表)は
  以下の様に条件式で結合してあげないと、何を何で更新するのか
  訳が分からなくなり正しく動作しない。
┌──────────────────────────────────────┐
│UPDATE [出力表]                                                             │
│    SET [列] = [入力表].[列]                                                │
│    FROM [入力表]                                                           │
│    WHERE [入力表].[キー] = [出力表].[キー];                                │
└──────────────────────────────────────┘
    以下だと更新されたが意図した更新はできない。
  ┌────────────────────────────────────┐
  │UPDATE [出力表]                                                         │
  │    SET [列] = [入力表].[列]                                            │
  │    FROM [入力表]                                                       │
  └────────────────────────────────────┘
    どうも[入力表]の一件目ですべてを更新したりしているようだが(たまたまか)。
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  但し、更新先と更新元が同じ場合は、同じ表を操作することになるので結合条件不要。
┌──────────────────────────────────────┐
│UPDATE [出力表]                                                             │
│    SET [列] = [出力表].[列]                                                │
│    FROM [出力表]                                                           │
│    WHERE [出力表].[キー] = [出力表].[キー];                                │
├──────────────────────────────────────┤
│UPDATE [出力表]                                                             │
│    SET [列] = [出力表].[列]                                                │
│    FROM [出力表];                                                          │
└──────────────────────────────────────┘
  (これだと更新により値が変わらないので意味がないが、原則として覚えておく)

  なお、「FROM」句の表が一つであれば、別名をつけることもできる。
┌──────────────────────────────────────┐
│UPDATE [出力表]                                                             │
│    SET [列] = [別名].[列]                                                  │
│    FROM [出力表] AS [別名];                                                │
└──────────────────────────────────────┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  自己結合で「FROM」句に複数の更新先(出力表)が出現する場合は
  そのうちどれが「UPDATE」文の更新先(出力表)と一致するのか明示する必要があり
  「UPDATE」文は「AS」で別名をつけられない経緯からして
  「FROM」句側もどれか一つ別名をつけないものを用意する必要がある。
┌──────────────────────────────────────┐
│UPDATE [出力表]                                                             │
│    SET [列] = [別名].[列]                                                  │
│    FROM [出力表],                                                          │
│         [出力表] AS [別名]                                                 │
│    WHERE [別名].[キー] = [出力表].[キー];                                  │
└──────────────────────────────────────┘

  上記はOKだが、以下はお互いに譲り合ってる(別名を名乗ってる)のでNG。
┌──────────────────────────────────────┐
│UPDATE [出力表]                                                             │
│    SET [列] = [別名2].[列]                                                 │
│    FROM [出力表] AS [別名1],                                               │
│         [出力表] AS [別名2]                                                │
│    WHERE [別名2].[キー] = [別名1].[キー];                                  │
├──────────────────────────────────────┤
│UPDATE [出力表]                                                             │
│    SET [列] = [別名2].[列]                                                 │
│    FROM [出力表] AS [別名1]                                                │
│        INNER JOIN [出力表] AS [別名2]                                      │
│          ON [別名2].[キー] = [別名1].[キー];                               │
└──────────────────────────────────────┘
  「INNER JOIN」なら回避できるかと思ったが、やっぱりそれもNG。

  但し、「UPDATE」文で別名を(定義するのではなく)使用するという荒業もある。
┌──────────────────────────────────────┐
│UPDATE [別名1]                                                              │
│    SET [列] = [別名2].[列]                                                 │
│    FROM [出力表] AS [別名1],                                               │
│         [出力表] AS [別名2]                                                │
│    WHERE [別名2].[キー] = [別名1].[キー];                                  │
└──────────────────────────────────────┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  従ってまとめると、一件以下の「WHERE」句が必要な気がしないでもないが
  [別名]と[出力表]は(実体として)同じ表なので、必要ないということになる。
┌──────────────────────────────────────┐
│UPDATE [出力表]                                                             │
│    SET [列] = [入力表].[列]                                                │
│    FROM [出力表] AS [別名]                                                 │
│        INNER JOIN [入力表]                                                 │
│          ON [入力表].[キー] = [別名].[キー]                                │
│    WHERE [別名].[キー] = [出力表].[キー];                                  │
├──────────────────────────────────────┤
│UPDATE [出力表]                                                             │
│    SET [列] = [入力表].[列]                                                │
│    FROM [出力表] AS [別名]                                                 │
│        INNER JOIN [入力表]                                                 │
│          ON [入力表].[キー] = [別名].[キー];                               │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/特定の文字数で区切る
2015年01月22日
例えば、'あ1い2う3え4お'を「4文字」で区切る場合。
┌─────────┬─────────────────┬────────┐
│すべて            │SELECT [列]                       │'あ1い2う3え4お'│
┌─────────┬─────────────────┬────────┐
│左から 4文字の左側│SELECT LEFT([列], 4)              │'あ1い2'        │
├─────────┼─────────────────┼────────┤
│左から 4文字の右側│SELECT RIGHT([列], LEN([列]) - 4) │      'う3え4お'│
├─────────┼─────────────────┼────────┤
│右から 4文字の左側│SELECT LEFT([列], LEN([列]) - 4)  │'あ1い2う'      │
├─────────┼─────────────────┼────────┤
│右から 4文字の右側│SELECT RIGHT([列], 4)             │        '3え4お'│
└─────────┴─────────────────┴────────┘
[列]の文字数を超える指定をしても問題ない(RIGHT()の場合も)。
但し、負数となるような指定をするとエラーとなる。
(上記で[列]が3文字の場合は、「LEN([列]) - 4」が「-1」(負数)となりエラー)
分類:MSSQL
MSSQL/表のマッチング
2015年01月19日
表の差異を比較し検出するSQL文。
┌──────────────────────────────────────┐
│SELECT ISNULL([右表].[キー], [左表].[キー]) AS [キー],                      │
│       [左表].[比較列]                      AS [左列],                      │
│       [右表].[比較列]                      AS [右列]                       │
│    FROM [左表]                                                             │
│        FULL JOIN [右表]                                                    │
│          ON [右表].[キー] = [左表].[キー]                                  │
│    WHERE [右表].[比較列] IS NULL              -- 左のみのもの              │
│       OR [左表].[比較列] IS NULL              -- 右のみのもの              │
│       OR [右表].[比較列] <> [左表].[比較列];  -- 差異があるもの            │
└──────────────────────────────────────┘
分類:MSSQL
前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 次へ