MW211 EXIT

devlog
MSSQL/数値変換
2015年03月10日
文字列を数値変換する場合、例えば先頭2文字を抜き出し数値変換する場合、
単純に組み合わせれば以下のような形が考えられる。
┌──────────────────────────────────────┐
│CONVERT(int, LEFT([列], 2))                                                 │
└──────────────────────────────────────┘
しかしながら、これだと数値変換できなイレギュラーなケースでエラーとなってしまう。

そういったことに対応できる堅牢な手段となると、以下がある。
┌──────────────────────────────────────┐
│TRY_CAST(LEFT([列], 2) AS int)                                              │
└──────────────────────────────────────┘
変換に失敗した場合はエラーにせず「NULL」にしてくれる。
但し、うまくいってしまい「0」になる場合もあるから注意。
(ExcelVBAの「Val()」と似たようなものだ)
分類:MSSQL
MSSQL/ストアドプロシージャの戻り値確認
2015年03月09日
「SQL Server Management Studio」のクエリにて、
ストアドプロシージャの戻り値を確認する方法。
┌──────────────────────────────────────┐
│DECLARE @変数 [int];                                                        │
│EXECUTE @変数 = [ストアドプロシージャ];                                     │
│PRINT @変数;                                                                │
└──────────────────────────────────────┘
変数を用意し、代入してPRINT出力する。
代入は「EXECUTE」とストアドプロシージャの間に代入文を挿入する。
分類:MSSQL
MSSQL/日付変換
2015年03月06日
「日付」と「年・月・日」の変換は以下の通り。
┌──────────────────────────────────────┐
│日付 ← DATEFROMPARTS(年, 月, 日)                                           │
├──────────────────────────────────────┤
│年   ← DATEPART(YEAR, 日付)                                                │
│月   ← DATEPART(MONTH, 日付)                                               │
│日   ← DATEADD(DAY, 日付)                                                  │
└──────────────────────────────────────┘

「日付」を「週(年内週)」(その年の何週目か)に変換するのは以下の通り。
┌──────────────────────────────────────┐
│年内週 ← DATEPART(WEEK, 日付)                                              │
└──────────────────────────────────────┘

その逆(週から週の範囲を求める方法)は以下の通り。
┌──────────────────────────────────────┐
│週頭日付 ← DATEADD(DAY, 1 - DATEPART(WEEKDAY, 日付), 日付)                 │
│週末日付 ← DATEADD(DAY, 6, 週頭日付)                                       │
└──────────────────────────────────────┘

週の範囲がわかれば、「月内週」(その月の月週目か)がわかる。
┌──────────────────────────────────────┐
│年     ← DATEPART(YEAR, 日付)                                              │
│月     ← DATEPART(MONTH, 日付)                                             │
│月内週 ← DATEPART(WEEK, 日付)                                              │
│        - DATEPART(WEEK, DATEFROMPARTS(DATEPART(YEAR, 日付),                │
│                                       DATEPART(MONTH, 日付),               │
│                                       1))                                  │
│        + 1                                                                 │
├──────────────────────────────────────┤
│年     ← DATEPART(YEAR, 週頭日付)                                          │
│月     ← DATEPART(MONTH, 週頭日付)                                         │
│月内週 ← DATEPART(WEEK, 週頭日付)                                          │
│        - DATEPART(WEEK, DATEFROMPARTS(DATEPART(YEAR, 週頭日付),            │
│                                       DATEPART(MONTH, 週頭日付),           │
│                                       1))                                  │
│        + 1                                                                 │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/厳密なRANK()
2015年03月05日
大文字と小文字を区別する場合、「PARTITION BY」に「COLLATE Japanese」を使用する。
┌──────────────────────────────────────┐
│SELECT [キー]                                                               │
│       [集合キー],                                                          │
│       RANK() OVER(PARTITION BY [集合キー] COLLATE Japanese_CS_AS_KS_WS     │
│                   ORDER BY [キー] ASC) AS [順番]                           │
│    FROM [表];                                                              │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/厳密な「GROUP BY」
2015年03月04日
実は「GROUP BY」では大文字と小文字を区別しない。
┌──────────────────────────────────────┐
│SELECT [集計項目],                                                          │
│       COUNT([キー]) AS [件数]                                              │
│    FROM (VALUES                                                            │
│        (1, 'ABC'),                                                         │
│        (2, 'ABC'),                                                         │
│        (3, 'abc')                                                          │
│    ) AS [テストD] (                                                       │
│        [キー],                                                             │
│        [集計項目]                                                          │
│    )                                                                       │
│    GROUP BY [集計項目];                                                    │
└──────────────────────────────────────┘
例えば上記の場合、「ABC」が「3件」という結果になり、
「abc」も「ABC」扱いとなってしまう。

ということで、厳密に。
WHERE句で使う「COLLATE Japanese」を流用したいところだが、
「GROUP BY」句に付けたらエラーとなってしまう。

正解は、一旦SELECT文で受けてあげるという形をとればよい。
┌──────────────────────────────────────┐
│SELECT [集計項目],                                                          │
│       COUNT([キー]) AS [件数]                                              │
│    FROM (                                                                  │
│        SELECT [キー],                                                      │
│               [集計項目] COLLATE Japanese_CS_AS_KS_WS AS [集計項目]        │
│            FROM (VALUES                                                    │
│                (1, 'ABC'),                                                 │
│                (2, 'ABC'),                                                 │
│                (3, 'abc')                                                  │
│            ) AS [テストD] (                                               │
│                [キー],                                                     │
│                [集計項目]                                                  │
│            )                                                               │
│    )  AS [中間D]                                                          │
│    GROUP BY [集計項目];                                                    │
└──────────────────────────────────────┘
ある意味、変換関数を介する感じだ。
分類:MSSQL
MSSQL/GROUPING SETS
2015年03月03日
最近のMSSQL(SQL Server)には、「GROUPING SETS」という便利な関数がある。

これは、例えばある売上データを、日付で集計したいし、
人(営業マン)でも集計したいという場合があったとする。

こういう場合は、それぞれでSQL文を発行するのが最も簡単なやり方だ。

ただ、間が空くと、タイミングによって、結果が異なるリスクもあるので、
できれば1つのSQL文を発行することによって同時に取得したい.

となると、以下の様に「UNION ALL」を使って、たすき掛けなデータを作ることになる。
┌──────────────────────────────────────┐
│SELECT [キー1],                                                             │
│       NULL      AS [キー2],                                                │
│       SUM([値]) AS [合計]                                                  │
│    FROM [表]                                                               │
│    GROUP BY [キー1]                                                        │
│UNION ALL                                                                   │
│SELECT NULL      AS [キー1],                                                │
│       [キー2],                                                             │
│       SUM([値]) AS [合計]                                                  │
│    FROM [表]                                                               │
│    GROUP BY [キー2]                                                        │
└──────────────────────────────────────┘

これを簡単にやってくれるのが「GROUPING SETS」関数だ。
基本はこんな感じ。だいぶ見やすい。
┌──────────────────────────────────────┐
│SELECT [キー1],                                                             │
│       [キー2],                                                             │
│       SUM([値]) AS [合計]                                                  │
│    FROM [表]                                                               │
│    GROUP BY GROUPING SETS (                                                │
│                 [キー1],                                                   │
│                 [キー2]                                                    │
│             );                                                             │
└──────────────────────────────────────┘


複合キーだって、共通のサブ階層だってへっちゃら。

以下の様に応用ができる。
┌──────────────────────────────────────┐
│SELECT [キー1-1],                                                           │
│       [キー1-2],                                                           │
│       [キー2],                                                             │
│       SUM([値]) AS [合計]                                                  │
│    FROM [表]                                                               │
│    GROUP BY GROUPING SETS (                                                │
│                 ([キー1-1], [キー1-2]),                                    │
│                 [キー2]                                                    │
│             ),                                                             │
│             [キーx-3]                                                      │
│    ORDER BY [キー2]   ASC,  --NULLが先頭になるのを避けるため               │
│             [キー1-1] ASC,                                                 │
│             [キー1-2] ASC,                                                 │
│             [キーx-3] ASC;                                                 │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/件数の集計
2015年02月27日
以下の二つの案がある

【あらかじめ集計テーブルを作り結合する案】
┌──────────────────────────────────────┐
│SELECT [親表].[キー],                                                       │
│       ISNULL([子表].[件数], 0) AS [件数]                                   │
│    FROM [親表]                                                             │
│        LEFT JOIN (                                                         │
│           SELECT [外部キー],                                               │
│                  COUNT(*)   AS [件数]                                      │
│               FROM [子表]                                                  │
│               GROUP BY [外部キー]                                          │
│        ), 0) AS [子表]                                                     │
│          ON [子表].[外部キー] = [親表].[キー]                              │
└──────────────────────────────────────┘

【副問い合わせにて集計する案】
┌──────────────────────────────────────┐
│SELECT [親表].[キー],                                                       │
│       ISNULL((                                                             │
│           SELECT COUNT(*)                                                  │
│               FROM [子表]                                                  │
│               WHERE [子表].[外部キー] = [親表].[キー]                      │
│       ), 0) AS [件数]                                                      │
│    FROM [親表];                                                            │
└──────────────────────────────────────┘

結果の種類が多い場合は前者が、少ない場合は後者が有利っぽいが、
最適化された結果、そんなに変わらないみたい。
#一見、後者は毎回集計しそうだが、あらかじめ集計テーブルを作っぽい

コピペという点では後者が有利っぽいが、性能的にはちょっとだけ前者がよさそう。
分類:MSSQL
MSSQL/実行計画
2015年02月26日
「SQL Server Management Studio」のクエリにて、実行計画を表示する設定。
┌──────────────────────────────────────┐
│SET STATISTICS PROFILE ON;                                                  │
└──────────────────────────────────────┘
元に戻すには以下の通り。
┌──────────────────────────────────────┐
│SET STATISTICS PROFILE OFF;                                                 │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/仮想表へのインデックス
2015年02月25日
┌──────────────────────────────────────┐
│CREATE VIEW [dbo].[仮想表] WITH SCHEMABINDING                               │
│AS                                                                          │
│    SELECT [列]                                                             │
│        FROM [dbo].[表]                                                     │
│;                                                                           │
├──────────────────────────────────────┤
│CREATE UNIQUE CLUSTERED INDEX [AK_仮想表] ON [dbo].[V_仮想表] (             │
│    [キー]                  ASC                                             │
│);                                                                          │
└──────────────────────────────────────┘
・仮想表作成時に「WITH SCHEMABINDING」をつける
  ・仮想表作成時にDB名を指定しない  ×「[DB].[dbo].[表]」→「[dbo].[表]」
    →つまりは他DBを絡めたビューには指定できないということ
・仮想表の中で参照している元の仮想表にも「WITH SCHEMABINDING」をつける
  →上記ルールが元の仮想表まですべて適用されるということ
・仮想表の中で参照している元の仮想表においては集約関数は使用不可
分類:MSSQL
MSSQL/秒の時分秒換算
2015年02月23日
「秒」を「時分秒」に換算するのに以下を使ってみた。
┌──────────────────────────────────────┐
│SELECT RTRIM(CONVERT(char(12),                                              │
│                     DATEADD(SECOND,                                        │
│                             [秒数],                                        │
│                             CONVERT(datetime, 0)),                         │
│                     108)                                                   │
│       )                                                                    │
└──────────────────────────────────────┘
ところが、24時間(86400秒)を超えると、「日」が繰り上がり「時」が「0」に戻る。
つまり本来「25時間」であるべきところが「(1日と)1時間」になってしまう。

MySQLだったら「SEC_TO_TIME()」という便利な関数があり、
「25時間」もへっちゃらなのだが。
┌──────────────────────────────────────┐
│SELECT SEC_TO_TIME(`秒数`);                                                 │
└──────────────────────────────────────┘

ということで、自前で実装してみた。
┌──────────────────────────────────────┐
│CREATE FUNCTION [dbo].[sec_to_time] (                                       │
│    @引数秒数               int                                             │
│) RETURNS varchar(max)                                                      │
│AS                                                                          │
│BEGIN                                                                       │
│    RETURN (                                                                │
│        SELECT CONVERT(varchar, FLOOR(@引数秒数 / 3600))                    │
│             + RIGHT(                                                       │
│                   RTRIM(CONVERT(char(12),                                  │
│                                 DATEADD(SECOND,                            │
│                                         ABS(@引数秒数),                    │
│                                         CONVERT(datetime, 0)),             │
│                                 108)),                                     │
│               6)                                                           │
│    );                                                                      │
│END;                                                                        │
└──────────────────────────────────────┘
分類:MSSQL
前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 次へ