Access VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


155 / 2272 ツリー ←次へ | 前へ→

【12799】クエリ:クロス集計について 木葉 15/4/10(金) 17:05 質問[未読]
【12800】Re:クエリ:クロス集計について かるびの 15/4/11(土) 2:18 回答[未読]
【12801】Re:クエリ:クロス集計について hatena 15/4/11(土) 5:19 回答[未読]
【12802】Re:クエリ:クロス集計について 木葉 15/4/11(土) 11:08 発言[未読]
【12806】Re:クエリ:クロス集計について 木葉 15/4/13(月) 17:16 質問[未読]
【12809】Re:クエリ:クロス集計について hatena 15/4/14(火) 1:01 回答[未読]
【12811】Re:クエリ:クロス集計について 木葉 15/4/14(火) 15:56 お礼[未読]

【12799】クエリ:クロス集計について
質問  木葉  - 15/4/10(金) 17:05 -

引用なし
パスワード
   こんにちは。先日は大変お世話になりました。
まだ日も経っておりませんがまたお世話になります。よろしくお願いします。


もしかするとVBAの質問ではないかもしれませんが…お付き合いいただけると嬉しいです。


●クロス集計の元になるもの:「作業内容管理」(クエリ)

「作業内容管理」の元になるテーブルは、以下の通りです。
・「作業内容」(*作業内容番号【O】、日付【D】、作業内容【T】、料金【T】、社員番号【T】)
・「社員」(*社員番号【O】、社員)

※()内はフィールド名、*は主キーです。
※データ型は〈【O】=オートナンバー型、【D】=日付型、【T】=短いテキスト、【N】=数値型〉です。
※「作業内容」の社員番号と「社員」の社員番号は結合させています。

●クロス集計で使うフィールド
・日付
・社員
・作業内容

一番左に日付、列見出しに社員を配置して、
1日の社員ごとの作業内容を見ることができるようにしたいのです。
雰囲気としては以下のような感じです。

(日付)    佐藤   本田   川村
2015/4/10 ○○○ ×××
2015/4/11      ▽▽▽ ◇◇◇
2015/4/13 ▲▲▲      ΘΘΘ

上のような形にすることはできました。
ただ、このままの状態だと、1日に1人の社員が1つの作業内容というデータならいいのですが、
1日に1人の社員が2回、3回と作業することもありますので、作業内容が入りきらないのです。

私の考えとしては、列見出しをふやしていきたいのですが…。
例えば佐藤さんが4/10に作業を2回したとしたら、

(日付)    佐藤   佐藤2  本田   川村
2015/4/10 ○○○ ●●● ×××

という感じです。

調べてもあまり出てこないのでどうしたものか…
そもそもこういう場合はクロス集計を使わないほうがいいのか…(クロス「集計」ですし)
でももしかするとVBAでできるのかも…?と思い質問させていただきました。

なんだか地に足がついていないような内容の質問で申し訳ありませんが、
ご提案などありましたら教えていただけたらと思います。

【12800】Re:クエリ:クロス集計について
回答  かるびの  - 15/4/11(土) 2:18 -

引用なし
パスワード
    クロス集計クエリ自体をいじくって、
>(日付)  佐藤   佐藤2  本田   川村
>2015/4/10 ○○○ ●●● ×××
というようなクロス集計クエリを作ることは、できないと思います。
 社員フィールドには、「佐藤2」なんていう値がないからです。


 もっと違った形でデータを表示した方がいいとは思います。
 例えば、サブフォームを使うとか、サブデータシートを使うなどの方法です。
 でも、一覧性に欠けてしまいますね。
 結局、良い方法は思いつきませんでした。


 なお、上記のような形のクロス集計クエリを作る方法がないわけではありません。
 クロス集計クエリの元になるクエリの段階で、例えば、「佐藤」を「佐藤2」に書き替えればいいのです。
 もうちょっと具体的に言うと、クロス集計クエリの元になるクエリ(Q集計元1)が

日付    作業内容 社員  
2015/4/10 ○○○  佐藤 
2015/4/10 ●●●  佐藤 
2015/4/10 ×××  本田
2015/4/11 ▽▽▽  本田
2015/4/11 ◇◇◇  川村
2015/4/13 ▲▲▲  佐藤
2015/4/13 ΘΘΘ  川村

となっているとすると、このクエリをいじって、

日付    作業内容 社員枝番付き  
2015/4/10 ○○○  佐藤 
2015/4/10 ●●●  佐藤2 
2015/4/10 ×××  本田
2015/4/11 ▽▽▽  本田
2015/4/11 ◇◇◇  川村
2015/4/13 ▲▲▲  佐藤
2015/4/13 ΘΘΘ  川村

となるようなクエリ(Q集計元2)を作るということです。


 問題は、同じ日付で2番目に出てくる「佐藤」を「佐藤2」に変える方法です。

 基本的にアクセスは、他のレコードの値によって自レコードの値を決める
ということができません。
 DLookup関数やDCount関数などのいわゆるD系関数を駆使すれば可能なのですが、
クエリでD系関数を使うと、クエリを開くのに時間がかかってしまいます。
 下手をすると、クエリを開くのに数分かかります。


 しかし、ワークテーブルを使えば、スピードアップできます。
 なお、ワークテーブルとは、一時的にデータを格納しておくテーブルのことです。

 ワークテーブルに「作業内容番号」と「社員枝番付き」を書き込んでいき、
このワークテーブルと作業内容テーブルを結合させたクエリを作ります。
 このクエリがQ集計元2です。


 ワークテーブルに「作業内容番号」と「社員枝番付き」を書き込む方法ですが、
まずは作業内容番号を書き込みます。
 具体的には、追加クエリを使って、Q集計元1から作業内容番号フィールドだけを
ワークテーブルに追加します。

 次いで、Q集計元1とワークテーブルとを
各「作業内容番号」フィールドで結合させ、
かつ、然るべく並び順を指定したレコードセットを作ります。

 そして、このレコードセットを先頭からループさせ、
「社員」フィールドの値に枝番を付けるかどうか、
付けるとしたら何番を付けるかを判断し、
「社員」フィールドの値に枝番を付けていきます。


 なお、この方法は、

   Recordset_連続番号の振り方:SampleFile071
ht tp://www.accessclub.jp/samplefile/samplefile_71.htm

を応用したものです。

【12801】Re:クエリ:クロス集計について
回答  hatena  - 15/4/11(土) 5:19 -

引用なし
パスワード
   かるびのさん提案の方法と考え方は同じですが、元テーブルに枝番フィールドを追加すればどうでしょうか。

社員毎連番は下記の関数を使えば1行コードを書くだけです。

グループ毎連番を自動入力する関数 - hatena chips
ht tp://hatenachips.blog34.fc2.com/blog-entry-428.html


SetSequenceNumber "枝番", "作業内容", "日付,社員番号"

クロス集計クエリの列見出しは、

式1: [社員] & IIf([枝番]=1,"",[枝番])

【12802】Re:クエリ:クロス集計について
発言  木葉  - 15/4/11(土) 11:08 -

引用なし
パスワード
   ▼かるびの様、hatena様


お返事ありがとうございます!
ご丁寧に教えていただき…大変助かります。


本題のお返事はまた分からない箇所ができ次第させていただきます。
おそらく理解しながら作っていくのに時間がかかるので…

取り急ぎ、ありがとうございました^^

【12806】Re:クエリ:クロス集計について
質問  木葉  - 15/4/13(月) 17:16 -

引用なし
パスワード
   遅くなってごめんなさい・・

考えすぎて訳が分からなくなっているだけかもしれませんが…

ひとまずワークテーブルと追加クエリまでは作りました。

>ワークテーブルと作業内容テーブルを結合させたクエリを作ります。
>このクエリがQ集計元2です。

とありますが、

> 次いで、Q集計元1とワークテーブルとを
>各「作業内容番号」フィールドで結合させ、

ここでもさらにクエリを作成したらいいのですか?


結合させるということは新たにクエリを作るとおっしゃっているように聞こえますし、
それだとQ集計元2を作る意味は…?
Q集計元1とワークテーブルを結合させたとしたら、どちらかを持て余す感じになるような気がします。
はたまた何か深い意味があるのか?

などと考えていたらますます こんがらがってきました…。


また、hatena様の
>元テーブルに枝番フィールドを追加すればどうでしょうか。
といいますのは、
かるびの様のおっしゃっているワークテーブルや追加クエリは使わずに、
Q集計元1に枝番フィールドを追加する、という解釈でいいのでしょうか?

載せていただいたページを見ていたのですが、
たくさんの知らない文に圧倒されてしまい…ただ文字通り見ているだけになってしまいました。

かるびの様からご提示いただいた方法と、どちらがわかりやすいか(というよりは見直したときに修正しやすいか)など考えていましたがそれもさっぱりです…。


右も左も分からないような者で申し訳ないですが、
何卒よろしくお願いします。

【12809】Re:クエリ:クロス集計について
回答  hatena  - 15/4/14(火) 1:01 -

引用なし
パスワード
   >>元テーブルに枝番フィールドを追加すればどうでしょうか。
>といいますのは、
>かるびの様のおっしゃっているワークテーブルや追加クエリは使わずに、
>Q集計元1に枝番フィールドを追加する、という解釈でいいのでしょうか?

クエリの元になっているテーブルつまり「作業内容」テーブルに「枝番」という数値型フィールドを追加してください。

> 載せていただいたページを見ていたのですが、
>たくさんの知らない文に圧倒されてしまい…ただ文字通り見ているだけになってしまいました。

下記の関数をコピーして標準モジュールに貼り付けてください。(リンク先のページにある関数です。)

'グループ毎の連番を入力する関数
'引数 FieldName:連番を格納するフィールド名(データ型は数値型)
'   TableName:対象のテーブル名またはクエリ名(パラメータクエリは不可)
'   GroupBy:グループ化するフィールド名(省略可能)
'        複数フィールドをカンマ区切りで指定可能
'        省略した場合は全レコードを通しての連番になります。
'   Orderby:並べ替えするフィールド名(省略可能)
'        SQLのORDER BY句内の式と同一
'        省略した場合は並び順は不定になります。
'   WhereCondition:抽出条件式(省略可能)
'        SQLのOWHERE句内の式と同一
'        省略した場合は全レコードが対象になります。
'使用上の注意: DAO ライブラリへの参照設定が必要です。
Public Function SetSequenceNumber( _
    FieldName As String, _
    TableName As String, _
    Optional GroupBy As String, _
    Optional Orderby As String, _
    Optional WhereCondition As String) As Boolean
  Dim rs As DAO.Recordset
  Dim c As Long, GCnt As Long, i As Long
  Dim strSQL As String, strOrderby As String
  Dim v() As String
  On Error GoTo ErrHdl

  SetSequenceNumber = True

  'SQL文生成
  strSQL = "SELECT " & FieldName
  If LenB(GroupBy) > 0 Then
    strSQL = strSQL & ", " & GroupBy
    strOrderby = "," & GroupBy
  End If
  strSQL = strSQL & " FROM " & TableName
  If LenB(WhereCondition) > 0 Then strSQL = strSQL & " WHERE " & WhereCondition
  If LenB(Orderby) > 0 Then strOrderby = strOrderby & "," & Orderby
  If LenB(strOrderby) > 0 Then strSQL = strSQL & " ORDER BY " & Mid$(strOrderby, 2)
  strSQL = strSQL & ";"
  Set rs = CurrentDb.OpenRecordset(strSQL, dbOpenDynaset)


  'グループ化するフィールド数分の動的配列確保
  GCnt = UBound(Split(GroupBy, ","))
  If GCnt > -1 Then ReDim v(GCnt)
  '連番書き込みループ
  Do Until rs.EOF
    For i = 0 To GCnt
      If v(i) = rs(i + 1) Then
      Else
        c = 0
        v(i) = rs(i + 1)
      End If
    Next
    c = c + 1
    rs.Edit
    rs(0) = c
    rs.Update
    rs.MoveNext
  Loop

Ext:
   On Error Resume Next
   rs.Close
  Set rs = Nothing
  Exit Function
ErrHdl:
  MsgBox Err & ":" & Err.Description
  SetSequenceNumber = False
  Resume Ext
End Function

この関数の内容は理解できなくても結構です。
使い方さえ理解すればOKです。
(ほとんどのPCユーザーはPCの仕組みは理解できていないが、PCは使えるというのと同じことです。)
使い方は、下記のコードを、クロス集計クエリを開く前に実行します。

SetSequenceNumber "枝番", "作業内容", "日付,社員番号"

これで、「作業内容」テーブルに「枝番」フィールドに、日付、社員番号毎に連番がふられます。

現状のクロス集計クエリの「列見出し」フィールドを下記に変更します。

式1: [社員] & IIf([枝番]=1,"",[枝番])

これで列見出しが下記のようになります。

 佐藤   佐藤2  本田   川村

もう少し具体的にいうと、例えば、
フォーム上にコマンドボタンを配置して、そのクリック時のイベントプロシージャを下記のように記述すればいいでしょう。

Private Sub コマンド_Click()

  SetSequenceNumber "枝番", "作業内容", "日付,社員番号"
  DoCmd.OpenQuery "クロス集計クエリ"

End Sub

これで希望のクロス集計クエリで開きます。

【12811】Re:クエリ:クロス集計について
お礼  木葉  - 15/4/14(火) 15:56 -

引用なし
パスワード
   ▼hatena さん:

お返事ありがとうございます!
>
>この関数の内容は理解できなくても結構です。
>使い方さえ理解すればOKです。
そうなのですね…理解できそうになかったので焦りました。


>フォーム上にコマンドボタンを配置して、そのクリック時のイベントプロシージャを下記のように記述すればいいでしょう。
>
>Private Sub コマンド_Click()
>
>  SetSequenceNumber "枝番", "作業内容", "日付,社員番号"
>  DoCmd.OpenQuery "クロス集計クエリ"
>
>End Sub

実行してみたところうまくいきました!

何から何まで任せっきりになるような形になってしまい申し訳ないです。


前回に引き続きやさしくご回答くださったかるびの様、hatena様、本当にありがとうございました^^

155 / 2272 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
1078189
(SS)C-BOARD v3.8 is Free