アナログCPU:5108843109

ゲームと音楽とプログラミング(酒と女とロックンロールのノリで)

('ω') < イザユケエンジニャー

ワークシートの最大行数、最大列数を取得

最大行数は Rows.Count
最大列数は Columns.Count
で取得できます。

' 使用例(1):「Sheet1」シートの全セルのデータや書式設定を削除
With ThisWorkbook.Sheets("Sheet1")
    Range(Cells(1, 1), Cells(Rows.Count, Columns.Count)).Clear
End With

' 使用例(2):可変値が範囲外にならないようなエラーチェック
Dim lRow As Long
Dim lCol As Long
lRow = ~~
lCol = ~~
If (0 < lRow And lRow <= Rows.Count) And (0 < lCol And lCol <= Columns.Count) Then
    ThisWorkbook.Sheets("Sheet1").Cells(lRow, lCol).Value = "hoge"
Else
    MsgBox ("範囲外やで")
End If

ボタンひとつで簡易grep

何度もgrepをかけるとき、いちいちウインドウ出てくることや
検索フォルダが「今開いているファイルの位置」になるのが非常に鬱陶しいので、
「あらかじめ指定されたフォルダ以下にて今選択している文字列をgrep」するマクロを作りました。
ショートカットキー割り当てておくと非常に楽です。

私は折り返し位置を81文字に設定しているので、
grep後に調整しています(コメントアウトしている部分)。

//grepフォルダ
$curdir = "C:\\hoge\\hage\\";

//grep対象ファイル(拡張子とか)
$filter = "*.c;*.cpp;*.h";

//選択範囲の文字列を取得
$word = gettext(seltopx,seltopy,selendx,selendy);

//grep
grep $word,$filter,$curdir,icon,subdir;

////折り返し位置変更
//config "w2000";


…という記事を旧ブログから移行してきたのですが、今読むと「ねぇよそんな作業」って感じです…。
かつては何故かすんげえ頻度ですんげえ大量にgrepする現場にいたので…。

VBAでセルの結合

セルを結合するには、MeageCellsプロパティを用います。

' A1~C3のセルを結合
Range("A1:C3").MergeCells = True

'現在選択している範囲を結合
Selection.MergeCells = True

ここで、結合したいセルのうち2つ以上にデータが入っていると、警告が表示されます。
これを無視して(表示させずに)結合したい場合は、
あらかじめ「Application.DisplayAlerts」をFalseに設定しておけばOKです。

Application.DisplayAlerts = False
Selection.MergeCells = True
Application.DisplayAlerts = True

また、逆にセルの結合を解除したい場合は、もちろんMergeCellsプロパティをFalseに設定すればOKです。

頭文字検索

MySQLを前提として書いています


用語集みたいなやつを作っていて、「あ行」「か行」…「英数字」という頭文字検索があったので、
調べてみたところLIKEかREGEXPが使えそうかなと思ったのですが…

LIKE
→複雑な正規表現は使用不可
→日本語に対応

REGEXP
正規表現使用可
→日本語に非対応

でした。

日本語対応版REGEXPであるMREGEXPというものもあるのですが、
会社の環境なのでインストールはちょっと…。

参考
mregexp - MySQLで日本語の正規表現を扱う


LIKEを使うとしたら

-- あ行
SELECT *
FROM `table`
WHERE `yomi` LIKE 'あ%'
   OR `yomi` LIKE 'い%'
   OR `yomi` LIKE 'う%'
   OR `yomi` LIKE 'え%'
   OR `yomi` LIKE 'お%'

-- 英数字
SELECT *
FROM `table`
WHERE `yomi` LIKE '0%'
   OR `yomi` LIKE '1%'
 -- (中略)
   OR `yomi` LIKE 'a%'
   OR `yomi` LIKE 'b%'
 -- (中略)
   OR `yomi` LIKE 'z%'

これはひどい

REGEXPを使うなら

-- あ行
SELECT *
FROM `table`
WHERE `hoge` REGEXP '^(あ|い|う|え|お)'
 
-- 英数字
SELECT *
FROM `table`
WHERE `hoge` REGEXP '^([0-9]|[a-z])'

という形になるはず。
ダメもとで試してみたところ、
例えば「あ行」の検索だと、確かに「あ~おのいずれかで始まる単語」はすべてヒットするのですが、
他の一部の単語もヒットしてしまいました。ほんとにダメかー。

ということで、日本語頭文字はLIKE検索・英数字はREGEXP検索、とすることにしました。

MREGEXPが使用可能ならこちらを使ってもよいと思いますが、LIKEの方が速度は速いようです。
データ量や正規表現の有無を考えて、MREGEXPにしろREGEXPにしろ、ご利用は計画的に。

あとは、根本的な対策として、インデックス用フィールドみたいなのを作っても良いかもしれませんね。
「あ行」「か行」みたいなのを読みから判断するのではなく、それ自体を持たせる形で。

ちなみにAccess等、一部のSQLではLIKEに正規表現使えるそうです。
うらやましい。

フィールドの順序を変更する

MySQLを前提として書いています


あるテーブルで、フィールドが「field_a」「field_b」がこの順に存在し、これを入れ替えたいときは以下のようにします。

ALTER TABLE テーブル名
MODIFY COLUMN `field_a` 型名 AFTER `field_b`;

テーブルの再構築

MySQLを前提として書いています


いつもは速いクエリが突然やたらと遅くなったので調べてみると、何故か適切なインデックスが使用されなくなっていた模様。
とりあえずインデックスを一旦削除して張り直すと戻りました。
(FORCE INDEX なんかも知ってはいますが、リリース済みのコードを直すのは(社内的に)面倒なので)

アホみたいにレコード数の多いテーブルなので定期メンテナンスできないか調べたところ、どうも空の ALTER TABLE を発行すると良さそう。

ALTER TABLE `テーブル名` ENGINE エンジン;

参考
nippondanji.blogspot.jp

とりあえず開発環境の同一構成テーブル(InnoDB、インデックスは11個)で試してみたところ、
約4万件に対して約2.8秒。

ちなみに本番環境は約500万件なので、同一構成のテーブルをもう一つ作成し
テストレコードをそのくらい入れて試してみたところ、15分。
結構きますね。

さらに全く別のテーブルでも試してみました。
約56万件、MyISAM、フルテキストインデックスあり。
1レコードあたりのサイズが大きい上に、フルテキストインデックスということでやはりかなりの時間がかかるようで
2時間近くかかりました。

…ということで定期メンテナンスが導入されたのですが、
空ALTERを発行することで逆に適切なインデックスが使われなくなってしまう箇所があり、
そこだけ一旦削除→再作成というステップを踏む羽目になっているのでした。なんでや。

ランダム文字列を生成する関数

以前に同タイトルの記事を書きましたがこちらはPHP版。

↓こちらはVBA版。まあこちらも基本ロジックは一緒なんですが…

honey8823.hateblo.jp

private function makeRandomStr($strlen = 1)
{
    // 使用可能な文字一覧
    $randomstr = "abcdefghijklmnopqrstuvwxyz1234567890";
    
    // 指定された文字数分繰り返してランダム文字列を作る
    $str = "";
    for ($i = 0; $i < $strlen; $i++)
    {
        $str .= $randomstr[rand(0, strlen($randomstr) - 1)];
    }
    
    return $str;
}

複雑な条件でGROUP BYする

MySQLを前提として書いています


下記Aのテーブルについて、
「idが4未満と4以上のグループに分けて、それぞれで一番小さいvalueをSELECT」
してBの結果が欲しいとき…

(A)test_table

id value
1 68
2 15
3 32
4 19
5 73
6 59

(B)

15
19

苦し紛れに以下のようなクエリを書いてみたら成功しました。

SELECT
  MIN(`value`) AS `min_value`
FROM
  `test_table`
GROUP BY
  `id` < 4
 ,`id` >= 4

GROUP句には条件式も使えるんですねー。
(ORDER句でも使えるのを知ってて思いついただけなので、それ実はダメだよ!みたいなの知ってる方いらっしゃいましたらこっそり教えてください…)

もちろん複数フィールドを使った条件式や、
等号不等号に限らず、IN等も使えます。
ちなみにGROUP句部分を下記のようにした場合、

GROUP BY
  `id` = 1
 ,`id` IN (2,3)

結果はこうなります。

68
15
19

条件から漏れたレコードについては勝手にまとめられるようですね。
使い方に応じて、不要なものはWHERE句できちんと省くとか、もしくはGROUP句での指定で漏れないようにするとか、きちんと考えて書かないとヘンな不具合の原因になりそうです。

Excelでよく使うショートカットキー

Excelのショートカットキーのうち、個人的によく使うものやすっかり忘れてたけどそういや便利だったわと思ったものをメモ。

自動入力系

ものすごく便利。
意外と知られていないのですがおすすめ。

  • 「Ctrl」+「D」上のセルのコピー(クリップボード非使用)
  • 「Ctrl」+「R」左のセルのコピー(クリップボード非使用)
  • 「Ctrl」+「;」今日の日付
  • 「Ctrl」+「:」現在の時刻

セル操作・参照系

  • 「Ctrl」+「+」セルの挿入
  • 「Ctrl」+「-」セルの削除
  • 「F2」選択しているセルの編集

シート操作・参照系

  • 「Ctrl」+「PageDown」次のシート
  • 「Ctrl」+「PageUp」前のシート
  • 「Shift」+「F11」シートの挿入

マクロ系

  • 「Alt」+「F8」マクロダイアログの表示
  • 「Alt」+「F11]VBEの起動

特定の文字以降を別の文字列に置き換える

具体的には、「メールアドレスの@以降を*でマスクする」ロジック。
文字列処理の関数を多数使用できて面白かったのでメモ。
ただ、PHPならもっと簡単なロジックが作れそうな気も…?

// 加工前のメールアドレス
$mail_address = "hoge@fuga.com";

// 加工後のメールアドレス
// (表示すると「hoge@*********」になる)
$masked_mail_address = substr($mail_address, 0, strpos($mail_address, '@') + 1) . str_repeat('*', strlen(strstr($mail_address, '@')));


使用している関数(リンク先は公式マニュアル)

  • strpos:文字列の検索
  • strlen:文字数の長さを求める
  • strstr:文字列の切り出し
  • substr:文字列の切り出し
  • str_repeat:文字列を繰り返す