2015年10月24日土曜日

[VBA] Set Nothing しても、Nothing にならない

VBA の参照型変数に Nothing を代入しても、Nothing にならないケースがある。
これは変数の定義方法が影響するためです。

変数の定義に New を付けると、オブジェクトを最初に参照したときにオブジェクトの新しいインスタンスが作成されます。
Dim Obj As New Collection
Obj.Add "Sample1"
とすると、2行目で Obj を参照するので、ここでインスタンスを作成した後で Add メソッドを実行します。

同様に、Set ステートメントで Nothing を代入しても、次にこのオブジェクト(変数)を参照したときに新しいインスタンスが作成されてしまいます。例えば以下の場合は・・・
Dim Obj As New Collection

Set Obj = Nothing
If Obj Is Nothing Then  ' ここで新しいインスタンスを作成する、Nothing にならない!
    Debug.Print "Nothing"
Else
    Debug.Print "Collection"  ' こちらを通過します
End If
こういった Nothing の判定が必要な場合は、変数の定義で New を指定せず、以下のようにします。
Dim Obj As Collection
Set Obj = New Collection

■ 参考資料

Dim ステートメント (Visual Basic)
https://msdn.microsoft.com/ja-jp/library/7ee5a7s1.aspx

2015年8月14日金曜日

ネットワーク先にあるCD/DVDを再生する。

光学ドライブが無いノートPC等では、ネットワークで繋がったPCのドライブからCD/DVDを使うことができるが、市販の音楽CDや、映画DVDを再生することができない。

■ 映画DVD(DVD-Video)の場合
DVD-Videoでは、映像データは VIDEO_TS フォルダの中にあるファイルなので、自分で複製して作ったDVD等のコピーガードが無いメディアならば、ネットワーク越しに各再生ソフトでアクセスできる。

ネットワーク越しでは、各再生ソフト/リッピングソフト(リッパー Ripper)は通常のファイル操作を行なってしまう。

「ネットワーク ドライブの割り当て」でも、「光学ドライブの共有」でも、ネットワーク越しだと「ネットワーク ドライブ」として認識するので、再生ソフトでは同じ動作(通常のファイル操作)になってしまい、コピーガードがあるとネットワーク経由で再生できない。ネットワーク経由で再生するならば、ネットワークメディアプレーヤー機器が必要です。

■ 音楽CD(CD-DA)の場合
拡張子が.cdaとなっているファイルが確認できるが、これは音声データではない。音楽データはCDトラックの内側から外側へ記録されているもので、PCにおけるファイルではない。
ネットワーク越しでは、各再生ソフト/リッピングソフトはファイルの操作を行なってしまうので、このままでは難しい。こちらもネットワーク経由で再生するならば、ネットワークメディアプレーヤー機器が必要です。

[Windows] MDACのバージョンを確認する方法

Microsoft Data Access Components (MDAC) のバージョンを確認する方法
https://support.microsoft.com/ja-jp/kb/301202

ただしサポートにある「Component Checker ツール」は古すぎて機能しないので、レジストリで確認するしかないだろう。現在では、MDAC から Windows DAC に入れ替わっているが、レジストリからのバージョン確認方法は有効でした。

Component Checker ツールのエラーメッセージ「Component Checker is not supported on Windows Vista and later Windows OS's, since MDAC files are protected on these platforms」

MDAC/Windows DAC を利用するアプリケーションの開発/動作環境
https://msdn.microsoft.com/ja-jp/data/gg607260.aspx

2015年8月2日日曜日

SoftBank 名義を変更したら、2年縛りが付いてしまう

ソフトバンク携帯(iPhone)の名義を変更したら、ホワイトプラン(i) が、ホワイトプランR(i)に変更されてしまった!
ホワイトプランR というのは、最近の政治・ニュースで問題化している「2年縛り」契約です。

新しいホワイトプラン(ホワイトプランR)のご案内
https://mk11.my.softbank.jp/mb/html/pc/price_plan/white_plan_r/

携帯「2年縛り」是正 総務省の有識者会議が提言へ
http://www.sankei.com/economy/news/150715/ecn1507150041-n1.html

古くから使い続けている 旧ホワイトプラン であれば、「2年契約」の縛りは無いので、例えば家族間で名義を変更するだけで「2年縛り」が付いてしまうのでは、今さら名義変更しないほうがいい。

SoftBankショップの説明としては、
・旧ホワイトプランと、ホワイトプランRは同じ内容
・旧ホワイトプランは、もう契約できない。

ただ自分で調べてみると、相当だまされていることが分かる。これは契約時に直ちに拒否しないと酷い目に遭います。
・本当に同じ内容? →「2年縛り」の有無が異なる。
・旧ホワイトプラン は、一旦は受付終了のアナウンスが流れたが、延期されて未だ終了していない。

一部料金プランおよび割引サービスの受付期間を延長
http://www.softbank.jp/mobile/info/personal/news/price_plan/20141126a/

ホワイトプラン(i)
http://www.softbank.jp/mobile/price_plan/iphone/white-plan/
なお、ご加入中のお客さまは受付終了後も継続してご利用いただけます。

解約する際の契約解除料はいくらですか?
http://faq.mb.softbank.jp/detail.aspx?cid=10604&id=10604
「2010年4月26日以前にホワイトプランへお申し込みの場合、解除料金はかかりません。」

2015年4月5日日曜日

[MSAccess] テーブルで表示のフォーマットを指定する

Microsoft Access で、テーブルのデータシート ビューの表示でフォーマット(書式)を指定する方法です。

テーブルの場合は、デザイン ビューを開いて、出力フォーマットを指定したいカラム(フィールド)のプロパティから、「書式」を変更します。

テーブルのデータに書式を設定する
https://support.office.com/ja-jp/article/テーブルのデータに書式を設定する

クエリも同様にデザイン ビューを開いて、フィールドを選択して「書式」を変更することで変更できます。いずれも Null の表示には影響しません。

2015年4月4日土曜日

[MSAccess] SELECT INTO でデータ型を指定したい

Microsoft Access の SQL では、SELECT INTO ステートメントとは、テーブルを作成して検索結果を挿入します。作成するテーブルにおけるフィールドのデータ型は、クエリの元になるテーブルのフィールドのデータ型とフィールド サイズを継承しますが、SQL 関数などを使用すると適切なデータ型に判定されません。(多くはテキスト型になる)

■ データを直接指定した場合

以下の結果となりました。(Microsoft Access 2007)
SELECT
  0 As Col1,
  0.1 As Col2,
  50000 As Col3,
  '0' As Col4,
  #2015/04/01# As Col5,
  True As Col6,
  Null As Col7,
  IIF(True, 1) As Col8
INTO テーブル1
上記の実行結果
挿入する値データ型の判定結果
0長整数型 (Long)
0.110 進型 (Decimal)
50000長整数型 (Long)
'0'テキスト型 (Text)
#2015/04/01#日付/時刻型 (Date/Time)
True整数型 (Integer)
Nullバイナリ型 (Binary)
IIF関数長整数型 (Long)
今回は、それなりに判定されています。

■ データ型変換関数を使う場合

期待通りのデータ型に判定されていないなら、数値型等のデータ型を指定する場合は、データ型変換関数を使うことで判定を誘導できる。ただしデータ型変換関数では Null はエラーになってしまうため、Not Null 制約がある項目でしか使えない。
データ型変換関数データ型の判定結果
CBool(1)整数型 (Integer)
CByte(1)整数型 (Integer)
CCur(1)通貨型 (Currency)
CDate(1)日付/時刻型 (Date/Time)
CDbl(1)倍精度浮動小数点型 (Double)
CInt(1)整数型 (Integer)
CLng(1)長整数型 (Long)
CSng(1)倍精度浮動小数点型 (Double)
CVar(1)テキスト型 (Text)
CStr(1)テキスト型 (Text)
これも、それなりに判定されています。(完全ではない)

■ データ型変換関数を使う + Null 対策あり

Null 対策が必要であれば、ひと工夫してみると・・・、Null の場合はこの足し算結果が Null になるが、実行時エラーにはならない。
1 + CBool(True)倍精度浮動小数点型 (Double)
1 + CByte(1)倍精度浮動小数点型 (Double)
1 + CDate(1)日付/時刻型 (Date/Time)
1 + CDbl(1)倍精度浮動小数点型 (Double)
1 + CInt(1)倍精度浮動小数点型 (Double)
1 + CLng(1)倍精度浮動小数点型 (Double)
1 + CSng(1)倍精度浮動小数点型 (Double)
ほとんど「倍精度浮動小数点型」に判定されてしまった。

■参考資料

SELECT.INTO ステートメント (Microsoft Access SQL)
https://msdn.microsoft.com/ja-jp/library/office/ff192059.aspx

Access クエリで、CDec() 関数を使用すると、エラー メッセージ:「指定した式に含まれる関数で、引数の数が一致しません。」
http://support.microsoft.com/ja-jp/kb/225931/ja

データ型変換関数 (Visual Basic)
https://msdn.microsoft.com/ja-jp/library/s2dy91zy.aspx

Microsoft Access SQL リファレンス
https://msdn.microsoft.com/ja-jp/library/office/dn123881.aspx

[VBA] テーブルのフィールド名・データ型の一覧を表示

VBA で Microsoft Access テーブルのフィールド名、およびデータ型の一覧を表示するサンプルです。
ShowFields の引数に確認したいテーブル名を指定します。結果はイミディエイト ウィンドウに表示します。
Sub ShowFields(TableName As String)
    Dim Database As DAO.Database
    Dim Field As DAO.Field

    Set Database = CurrentDb
    For Each Field In Database.TableDefs(TableName).Fields
        Debug.Print Field.Name & vbTab & GetTypeName(Field.Type)
    Next
End Sub

Function GetTypeName(Value As DataTypeEnum) As String
    Select Case Value
    Case DataTypeEnum.dbBigInt
        GetTypeName = "多倍長整数型 (Big Integer)"
    Case DataTypeEnum.dbBinary
        GetTypeName = "バイナリ型 (Binary)"
    Case DataTypeEnum.dbBoolean
        GetTypeName = "ブール型 (Boolean)"
    Case DataTypeEnum.dbByte
        GetTypeName = "バイト型 (Byte)"
    Case DataTypeEnum.dbChar
        GetTypeName = "文字型 (Char)"
    Case DataTypeEnum.dbCurrency
        GetTypeName = "通貨型 (Currency)"
    Case DataTypeEnum.dbDate
        GetTypeName = "日付/時刻型 (Date/Time)"
    Case DataTypeEnum.dbDecimal
        GetTypeName = "10 進型 (Decimal)"
    Case DataTypeEnum.dbDouble
        GetTypeName = "倍精度浮動小数点型 (Double)"
    Case DataTypeEnum.dbFloat
        GetTypeName = "浮動小数点型 (Float)"
    Case DataTypeEnum.dbGUID
        GetTypeName = "GUID 型 (GUID)"
    Case DataTypeEnum.dbInteger
        GetTypeName = "整数型 (Integer)"
    Case DataTypeEnum.dbLong
        GetTypeName = "長整数型 (Long)"
    Case DataTypeEnum.dbLongBinary
        GetTypeName = "ロング バイナリ型 (Long Binary)"
    Case DataTypeEnum.dbMemo
        GetTypeName = "メモ型 (Memo)"
    Case DataTypeEnum.dbNumeric
        GetTypeName = "数値型 (Numeric)"
    Case DataTypeEnum.dbSingle
        GetTypeName = "単精度浮動小数点型 (Single)"
    Case DataTypeEnum.dbText
        GetTypeName = "テキスト型 (Text)"
    Case DataTypeEnum.dbTime
        GetTypeName = "時刻型 (Time)"
    Case DataTypeEnum.dbTimeStamp
        GetTypeName = "タイムスタンプ型 (TimeStamp)"
    Case DataTypeEnum.dbVarBinary
        GetTypeName = "可変長バイナリ型 (VarBinary)"
    Case Else
        GetTypeName = "undefined"
    End Select
End Function

■ 参考資料

Field.Type プロパティ (DAO)
https://msdn.microsoft.com/ja-jp/library/office/ff845405.aspx

DataTypeEnum 列挙 (DAO)
https://msdn.microsoft.com/JA-JP/library/office/ff194420.aspx

[Windows] svchost の詳細を確認する

svchost.exe はタスク マネージャで複数確認できるプロセスで、比較的多くのメモリを使用していることが多い。svchost は Windows に登録しているサービスを実行するプロセスなので、svchost のプロセスの子プロセスとして複数のサービスのプロセスを持っている。

svchost がどのサービスを起動しているのか確認するには、複数の方法がある。

タスク マネージャで確認する

svchost.exe で現在実行されているサービスを確認するには
http://windows.microsoft.com/ja-jp/windows/what-is-svchost-exe

コマンドで確認する

tasklist コマンドで確認することができる。
tasklist /fi "imagename eq svchost.exe" /svc

ツールで確認する

Process Explorer ではプロセスツリーをGUIで確認することができる。
https://technet.microsoft.com/ja-jp/sysinternals/bb896653.aspx

2015年4月2日木曜日

[Access] 副問合せを外部結合する際のNull判定タイミング

Microsoft Access SQL における問題です。

副問合せもしくは別のクエリを外部結合した場合に、外部結合側にある Null 判定が動作するタイミングが副問合せの検索段階で終わっておらず、どうやら外部結合後に動作するために想定外の結果が返ることがある。

(例)今月購入して、発送日がNull(未発送)の取引を探す

サンプルデータ

顧客マスタ
顧客番号名前
01顧客01
02顧客02

購入履歴
顧客番号購入日発送日
012015/04/01Null
022014/04/012014/04/03

副問合せを外部結合するSQL

SELECT 顧客マスタ.顧客番号, 今月度.発送状況
FROM 顧客マスタ
LEFT OUTER JOIN (
  SELECT
    顧客番号,
    IIf(発送日 Is Null, '未発送') AS 発送状況
  FROM 購入履歴 
  WHERE #2015/04/01# <= 購入日
) AS 今月度 ON
  顧客マスタ.顧客番号 = 今月度.顧客番号;

予想される結果

顧客番号発送状況
01未発送
02Null

Access SQL での実行結果

顧客番号発送状況
01未発送
02未発送

考察

これは外部結合側でNull判定をする場合に問題となる。

外部結合であると「顧客02」は今月の購入履歴レコードが無いため、副問合せの結果(発送状況)は通常なら Null であると思われる。
しかし、副問合せにある IIf 関数が動作するタイミングがどうやら「副問合せの検索段階」ではなく「外部結合後」であるため、発送日が Null と判定されて「見発送」となってしまう。これは外部結合の結果について、副問合せ内の IIF 関数が判定していると言える。

[Access] SQLでSUMIF関数を使いたい

Excel には SUMIF 関数があるが、Access の SQL関数には同等なものが見当たらない。ただし、SUM と IIF 関数を合わせて同等なものを実現すれば、副問合せを使わずに簡潔に実現できる。

(例)デジタルコンテンツを除いて在庫数を算出する。
デジタルコンテンツの在庫数はゼロとするが、これ以外は「入荷数 - 販売数」を在庫数とする。

SELECT
  商品名,
  SUM(IIF(商品区分='デジタルコンテンツ', 0, 入荷数 - 販売数)) As 在庫数
FROM 商品
GROUP BY 商品名

2015年3月30日月曜日

[Excel] 時刻を使うグラフ軸でメモリ間隔の調整

Excelで時間/時刻をグラフに軸に使用する場合は、目盛間隔のデフォルトはExcelが自動的に調整するので、概ねキリの良い目盛間隔にならない。

また1日(24H)を1とする数値で表現しているので、目盛間隔を分かりやすく調整するには時刻の少数値を指定する必要がある。これはグラフの「軸のオプション」から以下の目盛間隔を指定すれば良い。

(表)Excelの目盛間隔のサンプル一覧
目盛間隔算出式指定する値
24時間11
12時間1/20.5
6時間1/40.25
3時間1/80.125
1時間1/240.041666667
30分1/24/20.020833333
15分1/24/40.010416667
10分1/24/60.006944444
5分1/24/120.003472222
1分1/24/600.000694444
30秒1/24/60/20.000347222
15秒1/24/60/40.000173611
10秒1/24/60/60.000115741
5秒1/24/60/125.78703703703704E-5
1秒1/24/60/601.15740740740741E-5

5秒以下の指数表記は、そのまま使用できる。なお Excel2010 ならば計算式でも入力が可能であったが、Excel2013 では少数しか受け付けてくれないようです。

■ 参考資料

グラフの縦 (数値) 軸の目盛を変更する(Microsoft)
https://support.office.com/

2015年3月14日土曜日

[MSAccess] ナビゲーション ウィンドウの表示を更新する

VBAでテーブル等を作成した後は、未だナビゲーション ウィンドウに表示されていない。この場合にナビゲーション ウィンドウの表示を更新する方法です。

特定のテーブルを表示する方法
Call DoCmd.SelectObject(ObjectType:=AcObjectType.acTable, ObjectName:="テーブル名", InDatabaseWindow:=True)

ナビゲーション ウィンドウをリフレッシュして、最新の状態を表示する方法
Application.RefreshDatabaseWindow

[MSAccess] 開いているフォームを全て閉じる

Microsoft Access で開いているフォームを全て閉じる方法です。

Form を全て閉じるサンプル
Dim AccObj As AccessObject
For Each AccObj In CurrentProject.AllForms
  If AccObj.IsLoaded Then
    DoCmd.Close AcObjectType.acForm, AccObj.Name, AcCloseSave.acSaveNo
  End If
Next

■ 参考資料

CurrentProject.AllForms プロパティ
https://msdn.microsoft.com/ja-jp/library/office/ff193455.aspx

Is it possible to use VBA code to close all open objects (forms, tables etc.)?
http://bytes.com/topic/access/answers/614454-possible-use-vba-code-close-all-open-objects-forms-tables-etc

[MSAccess] 開いているテーブルを全て閉じる

Microsoft Access データシート ビューで開いているテーブル、クエリを閉じる方法です。以下は開いているテーブルを全て閉じるサンプルです。特定のテーブルだけ閉じるには、DoCmd.Close メソッドでテーブル名を引数で指定すればよい。

Table を閉じる場合
Dim AccObj As AccessObject
For Each AccObj In CurrentData.AllTables
  If AccObj.IsLoaded Then
    DoCmd.Close AcObjectType.acTable, AccObj.Name, AcCloseSave.acSaveNo
  End If
Next


Query を閉じる場合
For Each AccObj In CurrentData.AllQueries
  If AccObj.IsLoaded Then
    DoCmd.Close AcObjectType.acQuery, AccObj.Name, AcCloseSave.acSaveNo
  End If
Next


■ 参考資料

AllTables オブジェクト (Access)
https://msdn.microsoft.com/ja-jp/library/office/ff193974.aspx
データベースの開いているテーブルをすべて表示するには、AllTables コレクションの各 AccessObject オブジェクトの IsLoaded プロパティを使用します。

2015年2月13日金曜日

[MSAccess] クエリの入力には、1つ以上のテーブルまたはクエリが必要です

SELECT 句にサブクエリが含まれると、エラーとなる場合がある。

(エラーとなるサンプル)
SELECT
  Now As 日付,
  (SELECT Price FROM テーブル1 WHERE code='0001') As 時価

エラーメッセージ:[3067] クエリの入力には、1つ以上のテーブルまたはクエリが必要です。

Access SQL では、こういう場合に無用なダミーテーブルを準備する必要はない。ただし迂回策として、サブクエリの代わりに DLookup 関数を使う方法がある。

(修正したSQL)
SELECT
  Now As 日付,
  DLookup("Price", "テーブル1", "code='0001'") As 時価


■ 参考資料

[ACC2003] DLookup() の使い方、例、トラブルシューティング
http://support.microsoft.com/kb/285866/ja

2015年2月12日木曜日

[MSAccess] オブジェクトが正しくないか、現在設定されていません

CurrentDb メソッドを使って DAO オブジェクトの参照を取得した場合に、エラーが発生することが多い。

(エラーとなるサンプル)
Dim Table As DAO.TableDef
Set Table = CurrentDb.TableDefs("テーブル1")
Debug.Print Table.Name

エラーメッセージ:[3420] オブジェクトが正しくないか、現在設定されていません。

マイクロソフト サポート情報によると、これは CurrentDb メソッドの参照を明示的に変数に代入してから使用する必要がある、とのこと。

(改善例)
Dim DB As DAO.Database
Set DB = CurrentDb()
Dim Table As DAO.TableDef
Set Table = DB.TableDefs("テーブル1")
Debug.Print Table.Name


これだとバグとしか思えないんですが、言語仕様なんでしょうか・・

■ 参考資料

ACC: "Object Invalid or No Longer Set" Error Using CurrentDb
http://support.microsoft.com/kb/167173/ja

2015年2月9日月曜日

[MSAccess] 数値の出力フォーマット

SELECT 句などで数値の出力フォーマットを指定したい場合は、FormatNumber 関数が利用できます。

(例)
SELECT FormatNumber(12345, 2, True, False, True) As Value1
パラメータの意味は順に、出力する値/少数は2桁/小数点の左側の 0 を表示/負の値をかっこで囲まない/桁区切り記号を使用する

(出力結果)
Value1
---------
12,345.00


値がNullの場合は空欄で出力されます。

■ 参考資料

FormatNumber 関数 (Visual Basic)
https://msdn.microsoft.com/ja-jp/library/xfta99yt.aspx

[MSAccess] クエリ定義の SELECT で指定されている別名が循環参照を発生させています

関数を使う項目にカラムと同名で別名を付ける場合は、循環参照となってしまう。

(例)
SELECT Min(価格) As 価格
[エラーメッセージ] クエリ定義の SELECT で指定されている別名 '価格' が循環参照を発生させています。


これは、Microsoft Access では SELECT 句内の項目を参照できるために発生するもので、この解決方法としてはカラムがあるテーブル名を指定してやれば良い。

(対策例)
SELECT Min([商品].価格) As 価格


この仕様を利用すると、Oracle等では1階層のクエリでは実装できないことができる。

(例)
SELECT
  1 AS COL1,
  2 AS COL2,
  COL1 + COL2 AS COL3

ORA-00904: 'COL1' 無効な識別子です。

Microsoft Access であれば、SELECT 句内の項目は参照することができるので、このSQL は実行可能である。

上記SQLの結果
COL1 COL2 COL3
---- ---- ----
1    2    3

2015年2月7日土曜日

[MSAccess] テーブル レコードの並び順を変更する

リレーショナル型データベースにおいて、テーブルのレコードは通常ならば並び順は何も保証されないが、Microsoft Access のデータシート ビューでは、行の並び替えを指定することができる。

1.プロパティを指定する

テーブルのデザイン ビューを開いて プロパティシート を開き、「並び替え(OrderBy)」項目に、ソートする項目を記述します。複数の項目でソート順を指定する場合は、コンマで区切ります。
(例)col1, col2

VBA等のプログラム側から設定するには、DAO.Property の OrderBy プロパティを変更する
CurrentDb.TableDefs("テーブル1").Properties("OrderBy").Value = "フィールド1"

2.主キーを指定する

主キーの本来の用途ではありませんが、主キーはデータシート ビューにおいて暗黙的な並べ替えを行います。

3.(その他の手段)編集可能なクエリを使用する

クエリに並び替え(ソート順)を指定すれば、もちろんソートされます。またテーブルの結合や集約などが無いクエリであれば、クエリのデータシート ビューからデータの編集が可能です。

■ 参考資料

[ACC2003] MDB のレコードの並び順について
http://support.microsoft.com/kb/834927/ja

テーブルの概要
https://support.office.microsoft.com/ja-jp/article/%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E6%A6%82%E8%A6%81-78ff21ea-2f76-4fb0-8af6-c318d1ee0ea7?CTT=5&origin=HA102809525&CorrelationId=e502ec4d-3485-49d2-aabd-7fdf708a4eef&ui=ja-JP&rs=ja-JP&ad=JP#__migbm_12
並べ替え 1 つ以上のフィールドを選択して、データシート ビューでの行の既定の並べ替え順を指定します。