0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ACCESS VBA レコード数をカウントするクエリ、RefreshとRefreshDatabaseWindow

Last updated at Posted at 2018-03-21

地味だけど公式の説明はわかりづらい

TableNameという名前のTableにFieldnameという列があるとします(まんまだ)
公式はどう書いているかというと

1.[作成] タブの [その他] グループで、[クエリ デザイン] をクリックします。
Access のリボンの画像
2.[テーブルの表示] ダイアログ ボックスで、クエリで使用したいテーブルをダブルクリックし、[閉じる] をクリックします。
クエリ デザイナーの上の部分に、テーブルがウィンドウとして表示されます。
3.カテゴリ データを含むフィールドをダブルクリックし、カウントする値を含むフィールドもダブルクリックします。 その他の記述フィールドをクエリに含めることはできません。
4.[デザイン] タブの [表示/非表示] グループで [集計] をクリックします。
[集計] 行がデザイン グリッドに表示され、[グループ化] がクエリのフィールドごとに行に表示されます。
5.[集計] 行で、カウントしたいフィールドをクリックして、表示されるリストから [カウント] を選択します。
6.[デザイン] タブの [結果] グループで、[実行] をクリックします。
クエリの結果がデータシート ビューに表示されます。
7.必要に応じて、クエリを保存します。

わかりづらい…

VBAを使う

VBAはまず使えるように設定してください。
一つ空白のデータベースを作ります。

Tablenameというテーブルは1列Fieldnameという名前のフィールドがありデータはこんなだとします

A

A

B

B

B

C

レコード数をカウントすると、結果はこんな感じです。

A・・・2

B・・・3

C・・・1

テーブルのコード

それではまずテーブルを作りましょう。VBAを使えば簡単です。

vb.net

Sub Create_Table()

Dim cDB As DAO.Database: Set cDB = CurrentDb

Dim tdf As DAO.TableDef

Dim drs As DAO.Recordset

Dim fld As DAO.Field

Dim ar, iar As Long: ar = Split("A,A,B,B,B,C", ",")

DoCmd.RunSQL "Create Table TableName( FieldName  Text(255));"

Set drs = cDB.OpenRecordset("TableName")

For iar = LBound(ar) To UBound(ar)

drs.AddNew

drs.Fields(0).Value = ar(iar)

drs.Update

Next iar

End Sub

とりあえずテーブルはこんなです

では上の結果をクエリに表示させるにはどうするか。次はクエリをVBAで作りましょう


Sub Create_Query()

‘[VBAでクエリを作成する (DAO)](https://www.moug.net/tech/acvba/0040007.html)

Dim cDB As DAO.Database: Set cDB = CurrentDb

Dim Q As DAO.QueryDef

Dim sSQL As String

sSQL = _

"SELECT [TableName].Fieldname, Count([TableName].Fieldname) AS Fieldnameのカウント" & vbCrLf & _

"FROM [TableName]" & vbCrLf & _

"GROUP BY [TableName].Fieldname;"

Set Q = cDB.CreateQueryDef("Q_RecordCount", sSQL)

cDB.QueryDefs.Refresh ‘いつのAccessからか効かなくなっている命令。エラーにならずVersion違いに備え書いておく

Application.RefreshDatabaseWindow Mougにない命令Access2010以降効くのはこちら

End Sub

完成したクエリ

Fieldname Fieldnameのカウント

A 2

B 3

C 1

となります。

クエリのポイント

Select [TableName].FieldName まずここでテーブルからカウントするフィールドを選びます。

, Count([TableName].Fieldname) AS Fieldnameのカウント

コンマのあとが2列目の定義です。Countが関数で AS 以下が式の入っているフィールド名です。

FROM [TableName]

GROUP BY [TableName].Fieldname; ←セミコロンを忘れないこと

以下改行で、FROM テーブル名 GROUP BY テーブル名.フィールド名セミコロン

FROM テーブル名がクエリのもととなるテーブル名、
Group BY フィールド名でグルーピングをしています。ここが公式の手順の4に該当します。

改行は空白でも大丈夫です

つまり、

sSQL = "SELECT [TableName].Fieldname, Count([TableName].Fieldname) AS Fieldnameのカウント FROM [TableName] GROUP BY [TableName].Fieldname;"

と書いてもいいです。

絞り込んでカウントする

クエリで、Aだけ抜き出したい場合はSQLはどうなるでしょう。
クエリデザインで "A"といれてSQLビューで見てみます

SELECT TableName.Fieldname, Count(TableName.Fieldname) AS Fieldnameのカウント
FROM TableName
GROUP BY TableName.Fieldname
HAVING (((TableName.Fieldname)="A"));

とHavingが付きます。Havingが絞り込み条件だとわかります。このかっこの使い方複雑ですね。Accessのデザインビューはわかりやすく便利だとは言えませんが、こうしたSQLをわかりやすく入力する機能があるのです。

AとBならORで結びます

SELECT TableName.Fieldname, Count(TableName.Fieldname) AS Fieldnameのカウント
FROM TableName
GROUP BY TableName.Fieldname
HAVING (((TableName.Fieldname)="A")) OR (((TableName.Fieldname)="B"));

つまり通常のテーブルに応用するには

テーブルは手動でも作れますので、VBAを使わなくてもできますよね。
クエリもそうです。

SELECT [TableName].Fieldname, Count([TableName].Fieldname) AS Fieldnameのカウント FROM [TableName] GROUP BY [TableName].Fieldname;

ここでメモ帳(Notepad)を起動します。
メモ帳に上記のSQLをコピーし、TableNameとFieldNameを置換で書き換えます。
ACCESSに戻ります。
クエリデザインを開いて、テーブルを選択します。
SQLビューを開きます
メモ帳のSQLを選択してコピーし。それをSQLビューにコピーします。
データシートビューに切り替えます。
出来上がりを確認して名前を付けて保存します。
これで出来上がりです。

シンプルだと思いませんか?

ということをヘルプや公式に書いてほしいんだけどなあ。
あとSQLビューで置換が効かないのってどうにかならないのか。

公式の意味の分からないところ

カウントする値を含むフィールドもダブルクリックします。 その他の記述フィールドをクエリに含めることはできません。
これ何が言いたいかというと「カウントするフィールドだけにしろ」って意味ですね。

個人的な見解Application.RefreshDatabaseWindow

テーブルやクエリを作るのは3以上つある

Tableを作るには上記のSQLやCurrentDb.CreateTabledef、Appendと3つあります。この他にADOもあった気がしますが、
この際忘れます
クエリもそうですね。

SQLで作成しない場合はすぐに表示されない

前者の場合は、すぐ表示されますが、後2者の場合、F5キーを押さないと表示されない場合があります。

ネットではQuerydefs.refresh

クエリの場合、そんな時はQuerydefs.refreshとありますが、これも効かないことがあります。Application.RefreshDatabaseWindowが効きます。

QueryDefs.Refreshは本当に効くのか?

公式のQueryDefs.Refreshは書き方が冷たいです。Access 2010以降このオブジェクトのためにサポートされないとありあます。

QueryDefs.Refresh Method (DAO)

Not supported for this object.
Syntax


expression .Refresh
expression A variable that represents a QueryDefs object.

Remarks


You can't use the Refresh method with collections that aren't persistent, such as Connections, Databases, Recordsets, Workspaces, or the QueryDefs collection of a Connection object.

RefreshDatabaseWindow

一方RefreshDatabaseWindowは翻訳はおかしいので訂正が必要ですが、大変目的に沿っています
なんで翻訳がこんなめちゃくちゃなのか。

Application.RefreshDatabaseWindow メソッド
データベースオブジェクトが作成、更新、削除、名前の変更後にデータベース ウィンドウを更新します。(以下略)

というわけでまともに動くのはRefreshDatabaseWindowのようなのでこちらを使うか、QueryDefs.Refreshのあとに使うかした方が確実に画面が更新されます。

なのでMoug-VBAでクエリを作成する (DAO)
に乗っているコードはRefreshDatabaseWindow確実に動くというわけでもないのです。

原因はバージョンか

MougのコードはAccess97用です。
なので、バージョンで違うものと考えられます。
そこでAccess2010以降はVBAでSQL以外の方法でテーブルを作る場合は確実にRefreshDatabaseWindowを使うべきでしょう。

ただし現実は厳しい

こうしてExcelに変換して提示すると現実にはたいていキれられます。
「なんだこれは、DEFGHIJKLMNOPQRSTUVWXYZがないじゃないか?なにレコード数が0の場合は集計されない?君、馬鹿なことを言っちゃいかん。0も0として表示されないとダメじゃないか。」

まあAccessだともう一つテーブルを作らないと無理だし。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?