MW211 EXIT

devlog
SQL/初心者が犯しがちなミス
2015年06月19日
・TRUCATE TABLE文ではなく、DELETE文で全件削除
  →ロールバックに備えながら処理をするのでものすごく遅い
・相関副問い合わせではなく、内部結合で行抽出
  →抽出が先に行われない場合があり、ものすごく遅くなる
・インデックスを張らない
  →ものすごく遅い
分類:SQL
ExcelVBA/オートフィルタ連動マクロ
2015年06月17日
ExcelVBA/オートフィルタ連動マクロ
オートフィルタの設定に伴ってマクロを起動する方法。

オートフィルタ変更イベント的なものはないので
代わりに「SUBTOTAL()」と再計算イベントを複合して対応する。

つまり、「SUBTOTAL()」で行件数を算出するようにして(第一引数=3)、
オートフィルタで行数が変動するのを再計算イベントで捕捉するという感じ。

以下のような形となる。
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
【全表示の場合】
┌────┬──┬───┬───┬───┬───┐┌────┐
│抽出条件│キー│項目A │項目B │項目C │項目Z ││=SUBTOTAL(3,A:A)
├────┼──┼───┼───┼───┼───┤└────┘
│A       │A1  │あ    │      │      │ん    │
│A       │A2  │あ    │      │      │ん    │
├────┼──┼───┼───┼───┼───┤
│B       │B1  │      │い    │      │ん    │
│B       │B2  │      │い    │      │ん    │
├────┼──┼───┼───┼───┼───┤
│C       │C1  │      │      │う    │ん    │
│C       │C2  │      │      │う    │ん    │
├────┼──┼───┼───┼───┼───┤
│D       │D1  │      │      │      │ん    │
│D       │D2  │      │      │      │ん    │
└────┴──┴───┴───┴───┴───┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
【抽出条件を「A」のみにした場合】
┌────┬──┬───┬───┐┌────┐
│抽出条件│キー│項目A │項目Z ││=SUBTOTAL(3,A:A)
├────┼──┼───┼───┤└────┘
│A       │A1  │あ    │ん    │
│A       │A2  │あ    │ん    │
└────┴──┴───┴───┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
【抽出条件を「A」と「B」にした場合】
┌────┬──┬───┬───┬───┐┌────┐
│抽出条件│キー│項目A │項目B │項目Z ││=SUBTOTAL(3,A:A)
├────┼──┼───┼───┼───┤└────┘
│A       │A1  │あ    │      │ん    │
│A       │A2  │あ    │      │ん    │
├────┼──┼───┼───┼───┤
│B       │B1  │      │い    │ん    │
│B       │B2  │      │い    │ん    │
└────┴──┴───┴───┴───┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
【シートに記述するマクロ】
┌──────────────────────────────────────┐
│Option Explicit                                                             │
│Const X_抽出条件 As Long = 1                                                │
│'===========================================================================│
│'  再計算時のイベント(SUBTOTAL(3,A:A)の設定が必須)                          │
│'    オートフィルタの変更を検出できないため                                 │
│'===========================================================================│
│Private Sub Worksheet_Calculate()                                           │
│    Dim 配列 As Variant                                                     │
│    Dim 判定結果 As Variant                                                 │
│    With ActiveSheet                                                        │
│        If Not .AutoFilterMode Then                     ' フィルタ未設定    │
│            .Columns("A:G").Hidden = False                                  │
│            Exit Sub                                                        │
│        End If                                                              │
│        If .AutoFilter.Filters.Count < X_抽出条件 Then  ' キー列に未設定    │
│            Exit Sub                                                        │
│        End If                                                              │
│        If Not .AutoFilter.Filters(X_抽出条件).On Then  ' 絞り込み未設定    │
│            .Columns("A:G").Hidden = False                                  │
│            Exit Sub                                                        │
│        End If                                                              │
│        ' 抽出条件の配列化                                                  │
│        Select Case .AutoFilter.Filters(X_抽出条件).Count                   │
│            Case 1:                                                         │
│                配列 = Array(.AutoFilter.Filters(X_抽出条件).Criteria1)     │
│            Case 2:                                                         │
│                配列 = Array(.AutoFilter.Filters(X_抽出条件).Criteria1, _   │
│                             .AutoFilter.Filters(X_抽出条件).Criteria2)     │
│            Case Else:                                                      │
│                配列 = .AutoFilter.Filters(X_抽出条件).Criteria1            │
│        End Select                                                          │
│        ' 表示変更                                                          │
│        .Columns("A:G").Hidden = False                                      │
│        判定結果 = Filter(配列, "=A")                                       │
│        If UBound(判定結果) = -1 Then                                       │
│            .Columns("C:C").Hidden = True                                   │
│        End If                                                              │
│        判定結果 = Filter(配列, "=B")                                       │
│        If UBound(判定結果) = -1 Then                                       │
│            .Columns("D:D").Hidden = True                                   │
│        End If                                                              │
│        判定結果 = Filter(配列, "=C")                                       │
│        If UBound(判定結果) = -1 Then                                       │
│            .Columns("E:E").Hidden = True                                   │
│        End If                                                              │
│    End With                                                                │
│End Sub                                                                     │
│'===========================================================================│
└──────────────────────────────────────┘
分類:ExcelVBA
SQL/SQLインジェクション
2015年06月16日
┌──────────────────────────────────────┐
│SELECT 列 FROM 表 WHERE 検索列 = '■';                                      │
└──────────────────────────────────────┘
上記のようなSQL文を用意しておいて、画面から■の部分を入力してもらい、
任意の検索を行う場合を例にする。

以下のような値(文字列)を入力された場合…。
┌──────────────────────────────────────┐
│' OR 1 = 1;--                                                               │
└──────────────────────────────────────┘
そのままはめ込むと以下のようになってしまい(「--」以降はコメントとなる)
┌──────────────────────────────────────┐
│SELECT 列 FROM 表 WHERE 検索列 = '' OR 1 = 1;--';                           │
└──────────────────────────────────────┘
OR条件の「1 = 1」が如何なる時も成立してしまい全件ヒットする。

これが基本的なSQLインジェクション手法だ。

じゃ、「'」を「\'」に置換して、単なる文字にしてしまえばよいか?
┌──────────────────────────────────────┐
│SELECT 列 FROM 表 WHERE 検索列 = '\' OR 1 = 1;--';                          │
└──────────────────────────────────────┘
単なる「\' OR 1 = 1;--」という文字列で検索しにいくので成功!

それならこれでどうだ!
┌──────────────────────────────────────┐
│\' OR 1 = 1;--                                                              │
└──────────────────────────────────────┘
置換しなければ前出と同じなのだが、置換してしまうと以下のようになってしまう。
┌──────────────────────────────────────┐
│SELECT 列 FROM 表 WHERE 検索列 = '\\' OR 1 = 1;--';                         │
└──────────────────────────────────────┘
「'\\'」の部分が「\」という文字を意味することになり、
「1 = 1」が如何なる時も成立してしまう

ちなみに「'」を「''」に置換する場合も以下の通り。
┌──────────────────────────────────────┐
│SELECT 列 FROM 表 WHERE 検索列 = '\'' OR 1 = 1;--';                         │
└──────────────────────────────────────┘
こちらは「'\''」が「'」という文字を意味するが他は同じ。全て成立してしまう。

そんなに簡単な話ではないのだ。
分類:SQL
PostgreSQL/インデックスの使用状況
2015年06月15日
┌──────────────────────────────────────┐
│SELECT *                                                                    │
│    FROM "pg_stat_all_indexes"                                              │
│    WHERE "schemaname" = 'public';                                          │
├──────────────────────────────────────┤
│SELECT *                                                                    │
│    FROM "pg_statio_all_indexes"                                            │
│    WHERE "schemaname" = 'public';                                          │
└──────────────────────────────────────┘
基本は上記の二つ。

これを編集すると以下のような感じ。
┌──────────────────────────────────────┐
│SELECT "pg_stat_all_indexes"."relid",                                       │
│       "pg_stat_all_indexes"."indexrelid",                                  │
│       "pg_stat_all_indexes"."schemaname",                                  │
│       "pg_stat_all_indexes"."relname",                                     │
│       "pg_stat_all_indexes"."indexrelname",                                │
│       "pg_stat_all_indexes"."idx_scan",                                    │
│       "pg_stat_all_indexes"."idx_tup_read",                                │
│       "pg_stat_all_indexes"."idx_tup_fetch",                               │
│       "pg_statio_all_indexes"."idx_blks_read",                             │
│       "pg_statio_all_indexes"."idx_blks_hit"                               │
│    FROM "pg_stat_all_indexes",                                             │
│         "pg_statio_all_indexes"                                            │
│    WHERE "pg_stat_all_indexes"."indexrelid"                                │
│                                      = "pg_statio_all_indexes"."indexrelid"│
│      AND "pg_stat_all_indexes"."schemaname" = 'public'                     │
│    ORDER BY "pg_stat_all_indexes"."relname"      ASC,                      │
│             "pg_stat_all_indexes"."indexrelname" ASC;                      │
└──────────────────────────────────────┘
分類:PostgreSQL
PostgreSQL/使用量確認
2015年06月14日
  総使用量を確認する
┌──────────────────────────────────────┐
│SELECT SUM(`data_length` + `index_length`) / 1024 / 1024 AS `総使用量(MB)`  │
│    FROM `information_schema`.`tables`;                                     │
└──────────────────────────────────────┘
  DBごとの使用量を確認する
┌──────────────────────────────────────┐
│SELECT `table_schema`                                    AS `DB名`,         │
│       SUM(`data_length` + `index_length`) / 1024 / 1024 AS `使用量(MB)`    │
│    FROM `information_schema`.`tables`                                      │
│    GROUP BY `table_schema`                                                 │
│    ORDER BY SUM(`data_length` + `index_length`) DESC;                      │
└──────────────────────────────────────┘
分類:PostgreSQL
DB設計/年齢と誕生日に見るDB設計
2015年06月13日
【管理】
  ・「誕生日」から「年齢」を計算できるが、
    「年齢」からは「誕生日」を逆算できない
    よって、管理したいのは「誕生日」
    →値の価値を見極めること
【計算】
  ・「誕生日」と現在日から「年齢」を算出できるが、
    都度やっていては手間がかかり反応が遅い
    (あらかじめ算出しておいた)「年齢」を直接もっていれば速い
    但し、「年齢」は日々変わるので日次バッチ処理にて再計算する必要あり
    →CPUの性能向上により現実には気にならない差異ではあるが
      件数が膨大な場合、計算量が多い場合には馬鹿にならない
  ・「満年齢」なら日次処理が必要だが、「数え年」なら(元旦の)年次処理で済む
    →効率を優先しての前提条件の変更も選択肢としてはある
【入手】
  ・情報を入手しやすいのは「年齢」
    #例えば新聞記事においては、たまに関係者の「年齢」の記載があるが、
      「誕生日」まで記載されているのは稀
    →現実問題として、できること(入手できる情報)は限られている
  ・「年齢」とそれが公表された日を記録しておけば、
    ある程度「誕生日」を絞り込むことができる(生年など)
    →時には付加情報も管理すべし
  ・「年齢」と「公表日」の対の情報は複数に渡る場合も予想される
    →正規化の必要性
  ・「年齢」と「公表日」の情報は必須ではないし、ない場合が多い
    #「誕生日」がわかっていれば、「年齢」や「公表日」はそもそもいらない
    →表形式の限界(表の分離も必要)
分類:SQL
MSSQL/日時型の生成
2015年06月10日
年、月といったint型からdate型もしくはdatetime型を生成する方法。

date型を生成。
┌──────────────────────────────────────┐
│SELECT DATEFROMPARTS(年, 月, 日);                                           │
└──────────────────────────────────────┘

datetime型を生成。
┌──────────────────────────────────────┐
│SELECT DATETIMEFROMPARTS(年, 月, 日, 時, 分, 秒, ミリ秒);                   │
└──────────────────────────────────────┘
分類:MSSQL
MSSQL/日付を年度に変換
2015年06月08日
泥臭くやるしかないみたい(そもそも年度は統一されてないし)

以下は四月始まりの年度の場合。
┌──────────────────────────────────────┐
│SELECT [日付],                                                              │
│       CASE                                                                 │
│         WHEN MONTH([日付]) < 4 THEN YEAR([日付]) - 1                       │
│         ELSE                        YEAR([日付])                           │
│       END AS [年度]                                                        │
│    FROM [表];                                                              │
└──────────────────────────────────────┘
分類:MSSQL
ExcelVBA/ADODBのNULL
2015年06月07日
ExcelVBAのADODBでストアドプロシージャの引数に「NULL」を指定したい場合は?
┌──────────────────────────────────────┐
│With SQLコマンド                                                            │
│    .ActiveConnection = データベース                                        │
│    .CommandType = adCmdStoredProc                                          │
│    .CommandText = "PROCEDURE_ストアドプロシージャ"                         │
│    .NamedParameters = True                                                 │
│    .Parameters.Append .CreateParameter("@引数", adInteger, adParamInput)   │
│    .Parameters("@引数").Value = Null                                       │
│    .Execute                                                                │
│End With                                                                    │
└──────────────────────────────────────┘
まんま「Null」を代入!
分類:ExcelVBA
Excel/シングルクォーテーション
2015年06月06日
セルの先頭にシングルクォーテーション「'」を入力すると文字列になる。

数値でも「'123」とすれば、文字列扱いになる。

但し、先頭の「'」は表示されない。(数式バーでは表示されるが)

セルの接頭辞という別世界のデータになるためだ。(数式バーは「接頭辞+値」を表示)

セルの接頭辞は、ExcelVBAにおいては「セル.PrefixCharacter」で値を参照できる。
→「」もしくは「'」

セルの接頭辞に「'」が設定されているのをExcelVBAで除去するには、
値を再代入すればよい。
「セル.Value = セル.Value」
#「セル.PrefixCharacter = ""」みたいな直接の代入はできない。

数式バーで見える形に参照したい場合には、以下のような感じで
条件分岐してあげればよい。
┌──────────────────────────────────────┐
│If セル.PrefixCharacter <> "" Then                                          │
│    結果 = セル.PrefixCharacter & セル.Value                                │
│Else                                                                        │
│    結果 = セル.Value                                                       │
│End If                                                                      │
└──────────────────────────────────────┘

セル表示に「'」を付けたい場合には、
先頭の「'」を「''」を置換してあげればよいだろう。

ちなみに、「'」「Z」という接頭辞「'」がついているセルに値を代入した場合の挙動
  ・「A」を入力   → 「'」「A」  …接頭辞「'」は残ったまま
  ・「'A」を入力  → 「'」「A」  …接頭辞「'」が上書される
  ・「123」を入力 → 「」「123」 …接頭辞がなくなる
なので、
  ・「''」を入力  → 「'」「'」  …接頭辞「'」が上書される
ということで、「'」が雪だるま式に増えることはないようだ。
分類:Excel
前へ 1 2 3 次へ