MW211 EXIT

devlog
Excel/入力文字数制限
2014年12月19日
セルの入力文字数を制限するには、データの入力規則で設定すればよい。

データ>データの入力規則>データの入力規則
┌────────────────────────┐
│データの入力規則                                │
├────────────────────────┤
│┌──┐                                        │
││設定│                                        │
││    └───────────────────┐│
││条件の設定                                  ││
││  入力値の種類                              ││
││  ┌────────┬─┐                  ││
││  │文字列(長さ指定)│▼│  □空白を無視する││
││  └────────┴─┘                  ││
││  データ                                    ││
││  ┌────────┬─┐                  ││
││  │次の値以下      │▼│                  ││
││  └────────┴─┘                  ││
││  最大値                                    ││
││  ┌────────────┬─┐          ││
││  │16                      │  │          ││
││  └────────────┴─┘          ││
│└──────────────────────┘│
│┌──────┐    ┌─────┐┌─────┐│
││すべてクリア│    │    OK    ││キャンセル││
│└──────┘    └─────┘└─────┘│
└────────────────────────┘
分類:Excel
MSSQL/代入で該当なし例外対策
2014年12月18日
例えば、ストアドプロシージャにて、以下のような代入文とした場合…。
┌──────────────────────────────────────┐
│DECLARE @変数  int                                                          │
├──────────────────────────────────────┤
│SELECT @変数 = [列]                                                         │
│    FROM [表]                                                               │
│    WHERE [抽出条件列] = 値;                                                │
└──────────────────────────────────────┘
WHERE条件で該当がないと、例外が発生してしまう。

LEFT JOINみたいに、該当なしは「NULL」になってくれるとありがたい場合、

ということで、以下のようなダミー表にLEFT JOINしてあげる。
┌──────────────────────────────────────┐
│DECLARE @変数  int                                                          │
├──────────────────────────────────────┤
│SELECT @変数 = [表].[列]                                                    │
│    FROM (SELECT 1 AS [ダミー列]) AS [ダミー表]                             │
│        LEFT JOIN (                                                         │
│            SELECT [列]                                                     │
│                FROM [表]                                                   │
│                WHERE [抽出条件列] = 値                                     │
│        ) AS [表]                                                           │
│          ON 1 = 1                                                          │
└──────────────────────────────────────┘
ま、これで、実現できることは実現できるのだが、これではちょっと美しくない。

もっと、シンプルに書けるのは以下の通り。
┌──────────────────────────────────────┐
│DECLARE @変数  int                                                          │
├──────────────────────────────────────┤
│SELECT @変数 = (                                                            │
│    SELECT [列]                                                             │
│        FROM [表]                                                           │
│        WHERE [抽出条件列] = 値                                             │
│);                                                                          │
└──────────────────────────────────────┘
分類:MSSQL
ExcelVBA/行列をまるっと移動
2014年12月16日
行列を16×16の範囲でまるっと移動するマクロ。
┌──────────────────────────────────────┐
│Sub 行をまるっと上へ移動()                                                  │
│    With ActiveCell                                                         │
│        If .Row > 1 Then                                                    │
│        .EntireRow.Cut                                                      │
│        .Offset(-1, 0).EntireRow.Insert Shift:=xlDown                       │
│        End If                                                              │
│    End With                                                                │
│End Sub                                                                     │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│Sub 行をまるっと下へ移動()                                                  │
│    With ActiveCell                                                         │
│        If .Row < 16 Then                                                   │
│        .EntireRow.Cut                                                      │
│        .Offset(2, 0).EntireRow.Insert Shift:=xlDown                        │
│        End If                                                              │
│    End With                                                                │
│End Sub                                                                     │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│Sub 列をまるっと左へ移動()                                                  │
│    With ActiveCell                                                         │
│        If .Column > 1 Then                                                 │
│        .EntireColumn.Cut                                                   │
│        .Offset(0, -1).EntireColumn.Insert Shift:=xlToRight                 │
│        End If                                                              │
│    End With                                                                │
│End Sub                                                                     │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│Sub 列をまるっと右へ移動()                                                  │
│    With ActiveCell                                                         │
│        If .Column < 16 Then                                                │
│            .EntireColumn.Cut                                               │
│            .Offset(0, 2).EntireColumn.Insert Shift:=xlToRight              │
│        End If                                                              │
│    End With                                                                │
│End Sub                                                                     │
└──────────────────────────────────────┘
分類:ExcelVBA
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
ExcelVBA/サブウインドウを開きつつ
2014年12月11日
サブウインドウを開きつつメインウインドウをいじりたい場合。

┌──────────────────────────────────────┐
│UserForm.Show                                                               │
└──────────────────────────────────────┘
通常は、サブウインドウが前面に表示されると奥にあるメインウインドウには
アクセスできない。
それはそれで使えるのだが、同時並行でメインウインドウも使いたい場合。

以下のように「vbModeless」をつける。
┌──────────────────────────────────────┐
│UserForm.Show vbModeless                                                    │
└──────────────────────────────────────┘
分類:ExcelVBA
ExcelVBA/ユーザ名とコンピュータ名を取得する
2014年12月09日
┌──────────────────────────────────────┐
│Private Function getユーザ名() As String                                    │
│    Dim objWSH As Object                                                    │
│    Set objWSH = CreateObject("WScript.Network")                            │
│    getユーザ名 = objWSH.UserName & "[" & objWSH.ComputerName & "]"         │
│End Function                                                                │
└──────────────────────────────────────┘
上記のような感じ。
「ユーザ名[コンピュータ名]」で取得できる。
分類:ExcelVBA
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
前へ 1 2 3 次へ