ぼくLog

子持ち、車持ち、マンション持ちの僕の日常を綴ります。車と、ラクをしたい一心で覚えたエクセルVBAを中心になりそうです。

エクセルデータベースにSQLでデータ追加!|エクセルVBA

f:id:yt4u:20180212111117j:plain

まず前編はこれ。

yt4u.hatenablog.com


ここでエクセルのシートをデータベースのテーブルと見なし、そこからデータを取得する方法をまとめたわけですが、今回は


データの追加もSQL使ってものすっごぉぉっく簡単に出来ちゃいますって話です。


前回同様この住所録を使って、ここにデータを追加してみたいと思います。

f:id:yt4u:20170102225905j:plain

(住所録はなんちゃって個人情報で生成したダミーデータです。)


データを追加するためのプロシージャを用意します

前回はGetRecordsetのプロシージャのみでしたが、データを追加(Execute)するためのプロシージャを用意します。

Private mstrErrDescription        As String

Private Const mcDataRangeName     As String = "rngXDB_DataBase"


'==========================================================
'Execute
'==========================================================
Public Function executeDB( _
                        ByRef objCN As Object, _
                        ByVal strSQL As String _
                        ) As Boolean
 
  
  executeDB = False
  
  
  On Error GoTo ERR_PROC
  
   
  objCN.execute strSQL
  
  
  executeDB = True
  
  
  GoTo END_PROC

ERR_PROC:

  mstrErrDescription = "Executeエラー"


END_PROC:
  
  
End Function


なお
Private mstrErrDescription As String
はエラー内容を返すための変数。


Private Const mcDataRangeName As String = "rngXDB_DataBase"
はシート上のデータテーブルに割り当てられたセル範囲名を示す定数。



データ追加してみます


で、早速データを追加してみます。

'==========================================================
'データ追加サンプル
'==========================================================
Public Sub addDataSample()

  Dim objCN             As Object
  Dim objRS             As Object
  Dim strSQL            As String
  Dim lngMaxNo          As Long
  
  
  'コネクションを確立
  
    Set objCN = GetXLSConnection(ThisWorkbook.FullName)
  
  
  'Noの最大値を取得
  
    strSQL = "SELECT"
      strSQL = strSQL & "  MAX([No]) AS MaxNo"
    strSQL = strSQL & " FROM " & mcDataRangeName
  
     
    If getRecordset(objCN, strSQL, objRS) = False Then
         
      GoTo ERR_PROC
    
    End If
  
  
    lngMaxNo = objRS!MaxNo
      
      
  
  '登録条件を作成
  
    strSQL = "INSERT INTO " & mcDataRangeName
    strSQL = strSQL & "("
      strSQL = strSQL & "  [No]"
      strSQL = strSQL & ", [名前]"
      strSQL = strSQL & ", [ふりがな]"
      strSQL = strSQL & ", [性別]"
      strSQL = strSQL & ", [年齢]"
      strSQL = strSQL & ", [誕生日]"
      strSQL = strSQL & ", [婚姻]"
      strSQL = strSQL & ", [血液型]"
      strSQL = strSQL & ", [都道府県]"
      strSQL = strSQL & ", [電話番号]"
      strSQL = strSQL & ", [携帯]"
      strSQL = strSQL & ", [キャリア]"
      strSQL = strSQL & ", [カレーの食べ方]"
    strSQL = strSQL & ")"
    strSQL = strSQL & "VALUES"
    strSQL = strSQL & "("
      strSQL = strSQL & "  " & lngMaxNo + 1
      strSQL = strSQL & ", '手酢十'"
      strSQL = strSQL & ", 'テスト'"
      strSQL = strSQL & ", '男'"
      strSQL = strSQL & ", 99"
      strSQL = strSQL & ", #2000/1/1#"
      strSQL = strSQL & ", '未婚'"
      strSQL = strSQL & ", 'AB型'"
      strSQL = strSQL & ", '東京都'"
      strSQL = strSQL & ", '00-0000-0000'"
      strSQL = strSQL & ", '999-9999-9999'"
      strSQL = strSQL & ", 'au'"
      strSQL = strSQL & ", '奥ルー・別口派'"
    strSQL = strSQL & ")"
  
  
    If executeDB(objCN, strSQL) = False Then
    
      GoTo ERR_PROC
    
    End If
  

  'データセル範囲を修正

    With wsXLSDataBase

      With .Range(mcDataRangeName)

        ThisWorkbook.Names.Add mcDataRangeName, .CurrentRegion

      End With

    End With
  
  
  GoTo END_PROC
  
ERR_PROC:

  MsgBox mstrErrDescription
  
  
END_PROC:
  
  'コネクションを閉じる
  
    Call CloseConnection(objCN)


End Sub


流れは、

  1. 新規追加するレコードのNoを現存するNoの最大値+1にするため、まずは現存するNoの最大値を取得
  2. 追加するレコードについてINSERT文を作成
  3. さっき用意したexecuteDBを実行してレコード追加。この時点でエクセルシート上にレコード追加完了
  4. データテーブルに割り当てられたセル範囲名(rngXDB_DataBase)の参照範囲を追加されたレコードを含むように修正



データ更新も可能です


INSERTが出来た次はUPDATEですね。

先ほどのデータテーブルでNoが最大値となっているレコードの名前をNULLにしたいと思います。


'==========================================================
'データ更新サンプル
'==========================================================
Public Sub updateDataSample()

  Dim objCN             As Object
  Dim objRS             As Object
  Dim strSQL            As String
  Dim lngMaxNo          As Long
  
  
  'コネクションを確立
  
    Set objCN = GetXLSConnection(ThisWorkbook.FullName)
  
  
  'Noの最大値を取得
  
    strSQL = "SELECT"
      strSQL = strSQL & "  MAX([No]) AS MaxNo"
    strSQL = strSQL & " FROM " & mcDataRangeName
  
     
    If getRecordset(objCN, strSQL, objRS) = False Then
         
      GoTo ERR_PROC
    
    End If
  
  
    lngMaxNo = objRS!MaxNo
  
  
  'Update文作成
  
    strSQL = "UPDATE " & mcDataRangeName
    strSQL = strSQL & " SET "
      strSQL = strSQL & "  [名前] = NULL"
    strSQL = strSQL & " WHERE 1 = 1 "
      strSQL = strSQL & " AND [No] = " & lngMaxNo
  
  
    If executeDB(objCN, strSQL) = False Then
    
      GoTo ERR_PROC
    
    End If

  
  GoTo END_PROC
  
ERR_PROC:

  MsgBox Err.Description
  
  
END_PROC:

  'コネクションを閉じる
  
    Call CloseConnection(objCN)


End Sub



レコードの削除もしちゃう?


INSERT、UPDATEと来たら次はDELETEですね。

これ、出来ません。
やろうとしても「この ISAM では、リンク テーブル内のデータを削除することはできません。」って怒られます。SHAZNAかよ!(古すぎて小声)




改めてコード全文を示します。

前回のコードも併せて改めて全文を載せます。


Option Explicit

Private Const adOpenDynamic       As Long = 2
Private Const adLockOptimistic    As Long = 3
Private Const adStateClosed       As Long = 0

Private mstrErrDescription        As String

Private Const mcDataRangeName     As String = "rngXDB_DataBase"


'==========================================================
'コネクションを返す
'==========================================================
Public Function GetXLSConnection(DataSource As String) As Object

  Dim objCN             As Object
  Dim strCNString       As String
  
  
  Set objCN = CreateObject("ADODB.Connection")
  
  
  strCNString = "Provider=Microsoft.Jet.OLEDB.4.0;" _
                        & "Data Source=" & DataSource & ";" _
                        & "Extended Properties=""Excel 8.0;" _
                        & "HDR=Yes"";"


  objCN.Open strCNString
  
  
  Set GetXLSConnection = objCN
  

End Function


'==========================================================
'GetRecordset
'==========================================================
Public Function getRecordset( _
                        ByRef objCN As Object, _
                        ByVal strSQL As String, _
                        ByRef objRS As Object _
                        ) As Boolean
 
  
  getRecordset = False
  
  
  On Error GoTo ERR_PROC
  
  
  Set objRS = CreateObject("ADODB.Recordset")
  
  
  objRS.Open strSQL, objCN, adOpenDynamic, adLockOptimistic
  
  
  getRecordset = True
  
  
  GoTo END_PROC

ERR_PROC:
      
  mstrErrDescription = "レコードセット生成エラー"


END_PROC:
  
  
End Function


'==========================================================
'Execute
'==========================================================
Public Function executeDB( _
                        ByRef objCN As Object, _
                        ByVal strSQL As String _
                        ) As Boolean
 
  
  executeDB = False
  
  
  On Error GoTo ERR_PROC
  
   
  objCN.execute strSQL
  
  
  executeDB = True
  
  
  GoTo END_PROC

ERR_PROC:

  mstrErrDescription = "Executeエラー"


END_PROC:
  
  
End Function


'==========================================================
'コネクション破棄
'==========================================================
Public Sub CloseConnection(objCN As Object)


  If objCN.State <> adStateClosed Then
  
    objCN.Close
  
  End If
  
  
  Set objCN = Nothing
  

End Sub


'==========================================================
'レコードセット破棄
'==========================================================
Public Sub CloseRecordSet(objRS As Object)


  If objRS.State <> adStateClosed Then
  
    objRS.Close
  
  End If


  Set objRS = Nothing
  
  
End Sub


'==========================================================
'データ取得サンプル
'==========================================================
Public Sub GetDataSample()

  Dim objCN             As Object
  Dim objRS             As Object
  Dim strSQL            As String
  Dim lngF              As Long
  
  
  'コネクションを確立
  
    Set objCN = GetXLSConnection(ThisWorkbook.FullName)
  
  
  '抽出条件を作成
  
    strSQL = "SELECT"                                           '抽出フィールド(項目)を指定
      strSQL = strSQL & "  [名前]"
      strSQL = strSQL & ", [ふりがな]"
      strSQL = strSQL & ", [電話番号]"
      strSQL = strSQL & ", MONTH([誕生日]) AS [誕生月]"
    strSQL = strSQL & " FROM " & mcDataRangeName                'データテーブルを指定
    strSQL = strSQL & " WHERE 1 = 1"                            '抽出条件
      strSQL = strSQL & " AND [性別] = '男'"                    '性別=男
      strSQL = strSQL & " AND [年齢] >= 30"                     '年齢=30歳以上
      strSQL = strSQL & " AND [年齢] <  50"                     '50歳未満
      strSQL = strSQL & " AND [婚姻] = '未婚'"                  '婚姻=未婚
  
  
  '抽出実行
     
    If getRecordset(objCN, strSQL, objRS) = False Then
         
      GoTo ERR_PROC
    
    End If
  
  
  '抽出結果を出力
  
    With wsXLSDataBase
    
      With .Range("rngXDB_DataTop")
      
        
        '出力エリアにある既存データを消去
        
          .CurrentRegion.ClearContents
          
        
        'フィールド(項目)名を出力
        
          For lngF = 0 To objRS.Fields.Count - 1
          
            .Offset(, lngF).Value = objRS.Fields(lngF).Name
          
          Next lngF
          
        
        'データを出力
        
          .Offset(1).CopyFromRecordset objRS
          
    
      End With
    
    End With
  
  
  GoTo END_PROC
  
ERR_PROC:

  MsgBox mstrErrDescription
  
  
END_PROC:

  'レコードセットを閉じる
  
    Call CloseRecordSet(objRS)
  
  'コネクションを閉じる
  
    Call CloseConnection(objCN)


End Sub


'==========================================================
'データ追加サンプル
'==========================================================
Public Sub addDataSample()

  Dim objCN             As Object
  Dim objRS             As Object
  Dim strSQL            As String
  Dim lngMaxNo          As Long
  
  
  'コネクションを確立
  
    Set objCN = GetXLSConnection(ThisWorkbook.FullName)
  
  
  'Noの最大値を取得
  
    strSQL = "SELECT"
      strSQL = strSQL & "  MAX([No]) AS MaxNo"
    strSQL = strSQL & " FROM " & mcDataRangeName
  
     
    If getRecordset(objCN, strSQL, objRS) = False Then
         
      GoTo ERR_PROC
    
    End If
  
  
    lngMaxNo = objRS!MaxNo
      
      
  
  '登録条件を作成
  
    strSQL = "INSERT INTO " & mcDataRangeName
    strSQL = strSQL & "("
      strSQL = strSQL & "  [No]"
      strSQL = strSQL & ", [名前]"
      strSQL = strSQL & ", [ふりがな]"
      strSQL = strSQL & ", [性別]"
      strSQL = strSQL & ", [年齢]"
      strSQL = strSQL & ", [誕生日]"
      strSQL = strSQL & ", [婚姻]"
      strSQL = strSQL & ", [血液型]"
      strSQL = strSQL & ", [都道府県]"
      strSQL = strSQL & ", [電話番号]"
      strSQL = strSQL & ", [携帯]"
      strSQL = strSQL & ", [キャリア]"
      strSQL = strSQL & ", [カレーの食べ方]"
    strSQL = strSQL & ")"
    strSQL = strSQL & "VALUES"
    strSQL = strSQL & "("
      strSQL = strSQL & "  " & lngMaxNo + 1
      strSQL = strSQL & ", '手酢十'"
      strSQL = strSQL & ", 'テスト'"
      strSQL = strSQL & ", '男'"
      strSQL = strSQL & ", 99"
      strSQL = strSQL & ", #2000/1/1#"
      strSQL = strSQL & ", '未婚'"
      strSQL = strSQL & ", 'AB型'"
      strSQL = strSQL & ", '東京都'"
      strSQL = strSQL & ", '00-0000-0000'"
      strSQL = strSQL & ", '999-9999-9999'"
      strSQL = strSQL & ", 'au'"
      strSQL = strSQL & ", '奥ルー・別口派'"
    strSQL = strSQL & ")"
  
  
    If executeDB(objCN, strSQL) = False Then
    
      GoTo ERR_PROC
    
    End If
  

  'データセル範囲を修正

    With wsXLSDataBase

      With .Range(mcDataRangeName)

        ThisWorkbook.Names.Add mcDataRangeName, .CurrentRegion

      End With

    End With

  
  GoTo END_PROC
  
ERR_PROC:

  MsgBox mstrErrDescription
  
  
END_PROC:
  
  'コネクションを閉じる
  
    Call CloseConnection(objCN)


End Sub


'==========================================================
'データ更新サンプル
'==========================================================
Public Sub updateDataSample()

  Dim objCN             As Object
  Dim objRS             As Object
  Dim strSQL            As String
  Dim lngMaxNo          As Long
  
  
  'コネクションを確立
  
    Set objCN = GetXLSConnection(ThisWorkbook.FullName)
  
  
  'Noの最大値を取得
  
    strSQL = "SELECT"
      strSQL = strSQL & "  MAX([No]) AS MaxNo"
    strSQL = strSQL & " FROM " & mcDataRangeName
  
     
    If getRecordset(objCN, strSQL, objRS) = False Then
         
      GoTo ERR_PROC
    
    End If
  
  
    lngMaxNo = objRS!MaxNo
  
  
  'Update文作成
  
    strSQL = "UPDATE " & mcDataRangeName
    strSQL = strSQL & " SET "
      strSQL = strSQL & "  [名前] = NULL"
    strSQL = strSQL & " WHERE 1 = 1 "
      strSQL = strSQL & " AND [No] = " & lngMaxNo
  
  
    If executeDB(objCN, strSQL) = False Then
    
      GoTo ERR_PROC
    
    End If

  
  GoTo END_PROC
  
ERR_PROC:

  MsgBox Err.Description
  
  
END_PROC:

  'コネクションを閉じる
  
    Call CloseConnection(objCN)


End Sub

SQL逆引き大全363の極意

SQL逆引き大全363の極意

加湿器迷子を経た結果オススメ出来る一台に出会いました。

乾燥した冬。加湿器は必須。
そんな加湿器を探し始めるとピンキリで一体どれにすればいいのか、、、かなり悩みますよね。


ぼくも色々試した結果、ちょうど良い一台に出会いました。


それがこれ。



超音波加湿器のbrumeシリーズです。


何故これが良い理由は至ってシンプルです。



この加湿器をオススメできる5つの理由


主張し過ぎないデザインが良い

おしゃれデザインの加湿器も世の中には数多あるけど、加湿器は部屋を加湿してナンボ。
求められるのは加湿機能でありデザインではなし。
物珍しいシェイプの加湿器を買ったところで、ものの数日でそのデザインに飽きること必至。
ならば普遍的なデザインが吉。

その点、このブルームはほぼ立方体。そして単色。

まったくムダのないデザインに仕上がっています。
だから飽きることがないというか、部屋の中にある棚や椅子のように当たり前のようにそこに鎮座します。


お手頃お値段がちょうど良い

加湿器も上を見れば1万2万当たり前。
プラズマクラスターだナノイーだと謳う商品もありますが、その効果をなかなか実感しにくいのも事実。
ならばそういった機能を求めるより、いっそのこと安さをトコトン求めるのもありですよね。

何よりもぼくは加湿器を消耗品だと思っています。

どんな加湿器でも買った最初のシーズンはそれなりに不満なく使えるもの。
でも2シーズン、3シーズン目となれば、ちょっと異臭がしてきたらり、カルキがこびりついたりするのが当たり前。
なんな状態で使い続けるのってちょっとしたストレスになりますよね。

だったら最初から加湿器を消耗品だと思って1シーズンのみ、少し引っ張ったとしても2シーズンだけ使って買い替えるのが合理的。

そうなると必然的に安いものに目が行くことになります。
少し値が張るものだとそう簡単に買い替えが出来ませんからね。
その点ブルームはお手頃価格。心置きなく買い替えが出来ます。


上部給水が便利!

上蓋外して水を注ぐだけだから超楽チン。
タンクを持ち上げて、ひっくり返して蓋外して、、、っていう面倒な作業が必要ありません。

この楽さを知ってしまったらもう後戻りはできません。


メンテナンスが◎

上部のタンクにせよ下部の受け皿にせよ、その内部は凹凸の少なくフラットな造りになっています。
そのため代替とのころに指が届くため掃除が非常にしやすいです。
ブラシなどを使わずにささっと洗えるので長く清潔に保つことが可能になります。


加湿性能は当然◎

弱・中・強の三段階調整ですが、相当乾燥していない限り「弱」~「中」で十分。 かなり乾燥している場合は「強」。あまり乾燥していない中「強」を使うと加湿器周りがちょっとびしょびしょ。。裏を返せば、それだけの加湿性能を持ってるということです(汗


これが買えるのはモダンデコ

ぼくが買ったのは楽天内のモダンデコです。


このショップは他にもシンプルでおしゃれな加湿器を取り揃えています。


たとえばWiLLシリーズ

これは立方体のbrumeシリーズと違って円柱タイプですが、性能はbrumeシリーズの小型番。
brumeのタンクが5Lに対してWiLLは1.5L。
部屋の大きさに合わせてbrumeとWiLLを使い分けてもいいかもしれません。



次にPRESSシリーズ

このタイプの加湿器は結構いろんなお店で見かけます。ハンズでも同種加湿器を扱っています。 たぶん出所は同じなのでしょうがモダンデコでも扱っています。

実はぼく、brumeの前はこの加湿器を使っていました。
何不自由なくしっかりと加湿器の仕事をしてくれました。
そして先述のとおりカルキのこびりつきが酷くなったのでbrumeに買い替えた次第です。



ぼくは使ったことがないのですがjunシリーズも気になります。

このシリーズは非常に独創的で、トップカバーを変えることで加湿器の能力を活かすことが可能です。

そのトップカバーを付けたバージョンがこちら。

これにより加湿範囲を広げることが可能になるようです。






もう一度言いますが加湿器は消耗品です。
性能てんこ盛りのお高い加湿器を買う必要は全くありません。
いくらいいのを買ってもあっという間に汚れが酷くなります。
酷い汚れをまとった蒸気が放出されることほど嫌なことはありません。場合によっては呼吸器系の病気を誘発します。
だから使い捨て前提でお安く、でもちょっとだけデザインに気を使った加湿器を選ぶのが大正解です。

配列?構造体?いやレコードセットでしょ!エクセルVBA

f:id:yt4u:20181204225012j:plain

二次元データの処理するとき、レコードセット使ってますよね??


え!?使ってない!!?


もし使ってなかったら、
今日から使い始めましょう!!



なんでレコードセットがいいの?

レコードセットってそもそもがデータベースから取得したデータの塊を格納するためのもの。 だからデータの扱いなら任せとけっていうオブジェクトなワケです。

じゃあ具体的にどんなメリットがあるのか配列と構造体配列と比較していきましょー。


だって列(フィールド)ごとにデータの型を決められる

二次元のデータで全ての列(フィールド)が同じデータ型になることってあまりないですよね。

例えばエクセルに株価のヒストリカルデータを表示させる場合でも、一番左の列が日付(Date)、次の列が株価で整数(Long)か小数点(Double)、さらにメモ用の列があったり(String)。

f:id:yt4u:20181123212411j:plain


レコードセットの場合、列(フィールド)ごとに型を決めることが出来ます(というか決める必要があります)。

Private Sub makeRecordset()

  Dim adoRS             As ADODB.Recordset
    
  Set adoRS = New ADODB.Recordset
  
  With adoRS
  
    With .Fields
    
      .Append "blDate", adDate
      .Append "blPrice", adDouble
      .Append "blMemo", adVarChar, 32, adFldIsNullable
    
    End With
  
    .Open
  
  End With
  
End Sub

レコードセットオブジェクトにフィールドを追加(Append)するときに、そのフィールドの名前と型を指定します。

Appendの後に続く引数で最初に来るのがフィールド名
ここでは日付、株価、メモの3つのフィールドが必要なので、それに相応するフィールドを用意しています(フィールド名頭のblはbokulogってことです^^)。

次の引数がそのフィールドの型。日付型、浮動小数点型、可変長文字列型を指定しています。
可変長文字列型は最大32文字。メモを書かない日もあることからNullもOK。
一方、営業日のみのデータを前提とした場合は日付と株価は必ず存在するためNullはNG。

ちょっと煩わしいコードに見えますが、慣れらたなんてことはねーっス



一方、配列の場合、指定できる型は一つだけ
だから、いくつもの型が入り混じっているときはVariantにするしかないんです。

コレ、キッチリ型を決めたいぼくには屈辱でしかないッス


次なる策は構造体配列。 これであれば列ごとに型を決めることが出来ます。

f:id:yt4u:20181123213149j:plain

複数の型が一堂に会するデータの塊を扱うときは構造体配列を使うのもひとつの手です。


だってデータの追加が超絶ラク


AddNew からの Update

この呪文を唱えるだけでOKです。

  With adoRS
  
    .AddNew
    
    !blDate = #11/23/2018#
    !blPrice = 21800
    !blMemo = "さらに上昇!"
    
    .Update
  
  End With

こんなカンジ。
至極簡単すわ~。



配列だとこんなにサクっとは出来ない。
Redim Preserve ってのはあるけど二次元配列の場合、行の追加って感じにはならずに、横方向、つまり列の追加ってことになってしまうのが悲しい現実。
だから配列の場合は、Preserve使って都度都度データを追加するというよりは、最初に格納するデータの範囲を確認して、それにフィットするサイズの配列を作ってからデータを入れていくって流れにならざるを得ない。


構造体配列の場合は、Redim Preserve でイケます。


いつもの作業を自動化したい人の Excel VBA 1冊目の本

いつもの作業を自動化したい人の Excel VBA 1冊目の本


だってデータを一気に吐き出せて幸せ


CopyFromRecordset

この呪文を唱えるだけでOKなんです。


例えばCodeNameがwsRecordsetのワークシートのセル(1, 1)を起点にデータを吐き出す場合は、こう書くだけでOK.

  With wsRecordset
  
    .Cells(1, 1).CopyFromRecordset adoRS
    
  End With

データの行数・列数を気にせずCopyFromRecordsetするだけで、レコードセットがすべてバコっと吐き出されます。



一方、配列の場合は、データを吐き出す前に行数・列数を把握してデータが吐き出されるセル範囲を指定する必要があります。

例えばこうです。

  With wsRecordset
  
    .Cells(1, 1).Resize(UBound(varData), UBound(varData, 2)).Value = varData
  
  End With

なんかクドイっすよね。


それでも配列の場合はデータを一気に吐き出せるだけまだマシ。

構造体配列の場合は、一気に吐き出す術がありません。
1つ1つ丁寧に出していくしかないんです。



だってデータにフィルタを掛けるのも楽勝


エクセルのオートフィルタってやつ。
レコードセットでも出来ます。しかもシンプルに。

先ほどの株価の表で22,000円未満の日だけ抽出したい。
こんな時はこれだけです。

  adoRS.Filter = "blPrice < 22000"

何やってるかすぐ分かりますよね。


さらに例えばいついつ以降のデータから抽出 でってのも簡単に加えられます。

  adoRS.Filter = "blPrice < 22000 AND blDate >= #2018/11/20#"

分かりやすっ!


さらに並び替え。

  adoRS.Filter = "blDate DESC"



コレ、配列あるいは構造体配列でやろうとするとここまで簡単には出来ない。

For~Next と If を組み合なんでわせて該当するデータ行を別の配列に入れたり、あるいはシートに吐き出していくしかありません。
ちょっとタラタラ長いコードが出来上がることになります。


たった1秒で仕事が片づく Excel自動化の教科書

たった1秒で仕事が片づく Excel自動化の教科書


データを加工するときはレコードセット一択


どう考えてもシート上のデータの扱いにおいてレコードセットに勝るものはなし。

巷にレコードセットを推奨する話があまりないのが不思議で仕方ないです。

とはいえぼくもレコードセットの存在を知ったのはデータベースを弄るようになってから。
それはまでは配列、あるいは構造体配列でFor~Nextでゴリゴリっとしたコード書きまくってました。

そんな中、レコードセットとの出会いはぼくに革命を齎しました(言い過ぎ)。
だってそれまでコードをグリグリ書いてやったことを、たった1行で出来ちゃうんだもの。
この感動、みなさんにも味わっていただきたいです。

yt4u.hatenablog.com

yt4u.hatenablog.com

IIJ mio を使い始めて7年が経ちました

ぼく、そこそこ長いこと格安SIMの王道、IIJ mio を使ってます。

IIJ mio 以前はドコモを10年以上使っていましたが、IIJ mio に切り替えて彼是7年。

IIJ mio 歴も長くなりましたが後悔は一切ありません


何よりも一番のメリットは安さ! * IIJ mio 導入後の月あたり平均コストは1,800円 * それまで月7,000円だったので5,200円のコストダウン!


しかもこれはひとり分です。

ぼくはずっとヨメの分も支払っています。なのでドコモ時代は月14,000円。
それが IIJ mio にしたことで月3,600円。ドコモ時代比10,000円のコストダウンになっています。

月10,000円。これはかなり大きい。
ちょっと美味しいもの食べに行けちゃいますよね。


IIJ mio のコスト内訳は?

まず IIJ mio の料金体系の中で、ぼくは音声SIMのミニマムスタートプランを使っています。
つまり月あたりのコストは基本料1,600円+通話料。

通話は基本LINEを利用。そのためほとんどの場合、通話料は掛かりません。 それでも通常の電話が必要な時は楽天でんわを利用しています。
ここはOCNでんわを使っても、みおふぉんダイアルを使っても通話料はほとんど変わらないので、どれを使っても何も問題ありません。


ドコモとのコストの違い

ドコモを利用していた時は、ぼく+ヨメ=月14,000円でした。
それが3,600円なので約1万円のコストダウン。

とはいえ、それは7年前との比較だから今とは料金体系とはちょっと違います。
これも問題ですよね。コロコロ料金体系が変わって基本的に従来からの契約者が割を食うのがメガキャリアの常。

一方、格安SIMは料金プランが至極シンプル。
ときどき新規契約獲得のためのキャンペーンが打たれて期間限定で異なる料金プラン(というか割引)が適用される時はありますが、ベースの料金プランは変わりません。
これって当たり前のようで当たり前ではないのが日本の携帯電話事情ですので、格安SIM料金の分かり易さは非常にありがたいものです。


格安SIMのメリット

改めて言うまでもありまえんが料金の安がが一番のメリット。

あとスマホ端末の選択肢が広いのもメリットです。
最新のiPhoneじゃなきゃゼッタイだめ!という人は格安SIMが最適解とはならないと思いますが、そうでなければ安くて必要十分のスペックを備えた端末がいくつもありますので、端末選びで困ることはないと思います。


格安SIMのデメリット

これは回線の細さだと思います。

格安SIMを提供するMVNOは大手キャリアの回線を間借りしている状態で、安さを確保するために回線の太さを犠牲にしています。

多くの人が集まってる場所、人が溢れる電車のホームや満員電車の中ではWebサイトの表示が遅くなりがちです。
そうした状況でなければ回線の細さを実感する場面はないのですが、ひとたびそうした状況に出くわすと自分が格安SIMを使っていることを再認識させられます。

防水カメラ『OLYMPUS Tough TG-5』はレンズの明るさが際立ってるよ!

まずはコレ。

f:id:yt4u:20180804095947j:plain
OLYMPUS デジタルカメラ Tough TG-5 渡嘉敷島

これは沖縄 渡嘉敷島の阿波連ビーチで撮影したものですが、
空の青さ、海の透明感、波打ち際の躍動感、どれを見ても最高じゃないですか!!

やっぱり渡嘉敷島サイコー!
っていう話はコチラのエントリーですが、 yt4u.hatenablog.com



今回はこの写真を撮ったカメラの話です。


それがコイツ。

高画質タフカメラの決定版。
撮影の軌跡を記録して臨場感を再現できるTG-5

謳い文句に偽りなし。



実写サンプル

f:id:yt4u:20180803221624j:plain
OLYMPUS Tough TG-5 渡嘉敷島 カクレクマノミ

f:id:yt4u:20180803222045j:plain
OLYMPUS Tough TG-5 渡嘉敷島

水中の撮影もバッチリ。



f:id:yt4u:20180811091813j:plain
OLYMPUS Tough TG-5 渡嘉敷島 無人

陸上でも当然、鮮やかな景色を切り取ってくれます。



f:id:yt4u:20180811092548j:plain
OLYMPUS Tough TG-5 ホテル日航アリビラ


f:id:yt4u:20180811092509j:plain
OLYMPUS Tough TG-5 シギラビーチ 花火

夜景や、特にブレやすい花火の撮影でもTG-5は力を発揮してくれます。



強みはF値2.0の明るいレンズ

綺麗に撮影できるポイントはなんと言っても明るいレンズ。

f:id:yt4u:20180811093024j:plain 進化した高画質/タフ性能 TG-5 | 防水デジタルカメラ T(Tough) シリーズ | オリンパス

だから色鮮やかな撮影が可能になるし、動きのある被写体、暗い場所でも使えます。



もちろん防水・防塵

f:id:yt4u:20180811093609j:plain

f:id:yt4u:20180811093620j:plain


海での撮影では防水・防塵は必須。

またカメラを片手に海で遊んでいれば、落としてしまう、ぶつけてしまう、そうした事態は容易に想像できます。
品名に「Tough 」を冠しているとおり、ちょとやそっとの衝撃ではビクともしません(実際、そんな衝撃を食らわせたことないんですけど、、、)。




過信は禁物!

防水・防塵、耐衝撃を兼ね備えてはいますが、過信は禁物です。
海の中は、カメラという精密機器にとって過酷な環境であることは間違いないです。
ちょっとした操作ミスなどで少しでも海水が入ればあっという間にダメになります。


なので、ぼくは海に入る前の移動時間などに、カメラからスマホ(ビーチに持ち込まないもの)にWifiで写真を送ってバックアップを取ってました。
Wifiで飛ばすためには事前にスマホアプリを入れておく必要がありますが、その準備さえすれば後は簡単操作でバックアップができるのもありがたいところです。



アクセサリーパーツも充実

レンズ、ホルダー、ストラップ、フラッシュなどのアクセサリーも充実しています。
使用環境に合わせた機能拡張がやりやすいのもTG-5の強み。

TG-5はそれ単体で防水性能を持ってますが、規定深度以上に潜れるように防水プロテクター(ハウジング)も用意されています。

OLYMPUS TG-5用 防水プロテクター PT-058

OLYMPUS TG-5用 防水プロテクター PT-058

深く潜らずともプロテクターがあれば安心感は格段に高まりますね!



TG-5はレンタルできるよ

ぼくは沖縄旅行に備えてTG-5をレンタルで用意していきました。

レンタルしたのはコチラ

www.rentio.jp

Rentioはカメラの充実、問い合わせ対応、梱包の丁寧さ、どれを見ても良いです。
配送の手間も極限まで省けるよう工夫してくれています。

普段、ほとんどの時間を陸上で生活しているので防水カメラを常備しておく必要はない場合は、こうしたレンタルサービスで充分かもしれませんね。

ですが、TG-5。その性能の高さや普段使いできるスタイルを兼ね備えていることから、一回レンタルでも使ってみると購入意欲がモリモリっと沸いてきちゃいますのでご注意を。