Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 11全般 : Microsoft 365)
アウトルック予定表のタイトルと本文をエクセルの表に転記したい
投稿日時: 22/10/19 23:03:39
投稿者: miyuukate

お世話になっています。
アウトルック予定表に登録されているタイトルと本文をエクセルシートの該当の日付に転記していきたいのですが…
エクセルシートの該当の日付を探して予定表の内容を転記させるのがわからない点
2行ごとに下に転記させていく点
がうまくいきません。
 
・アウトルックの個々の予定表には下記のように入力されています。
 例)10月1日の場合
 タイトル欄:タイトル1
 本文欄:3人
 
・エクセルシートは下記のような形です。
 
    A      B
     A社
1 10月1日  タイトル1
2        3人
3 10月2日    
4    
5 10月3日   タイトル2
6       4人
7       タイトル3
8       1人
9 10月4日    
10    
11 10月5日  タイトル3
12       2人
 
・下記が色々と参考しながら作成したコードで実行はされますが上記の2点がわからず該当のエクセルシートの表にうまく当てはめることができません。
 
Sub Outlookの予定表をエクセルシートへ転記()
 
    Dim olApp As Outlook.Application
    Dim olNamespace As Outlook.Namespace
    Dim olFolder As Folder
    Dim olConItems As Outlook.Items
    Dim olItem As AppointmentItem
     
    Dim wbBook As Workbook
    Dim wsSheet As Worksheet
    Dim lnContactCount As Long
    Dim strDummy As String
     
    Set wbBook = ThisWorkbook
    Set wsSheet = wbBook.Worksheets(1)
    wsSheet.Activate
     
    Set olApp = New Outlook.Application
    Set olNamespace = olApp.GetNamespace("MAPI")
    Set olFolder = olNamespace.GetDefaultFolder(olFolderCalendar)
    Set olConItems = olFolder.Items
    lnContactCount = 2
     
    Dim objAppt As AppointmentItem
    Dim strStart As String
    Dim strEnd As String
     
    strStart = Format("2022/10/1", "yyyy/mm/dd")
    strEnd = Format("2022/10/7", "yyyy/mm/dd")
    strEnd = DateAdd("d", 1, strEnd)
      
    Set olItem = olConItems.Find("[End] < """ & strEnd & """ AND [Start] >= """ & strStart & """")
     
    While TypeName(olItem) = "AppointmentItem"
        If olItem.Start >= strStart And olItem.End < strEnd Then
            With olItem
                Cells(lnContactCount, 2).Value = .Subject
                Cells(lnContactCount + 1, 2).Value = .Body
            End With
            lnContactCount = lnContactCount + 1
        End If
        Set olItem = olConItems.FindNext
    Wend
      
    Set olItem = Nothing
    Set olConItems = Nothing
    Set olFolder = Nothing
    Set olNamespace = Nothing
    Set olApp = Nothing
         
End Sub
[/code][/quote]
 
うまくエクセルの表に転記できずお手上げ状態です。
勉強不足でわかっていない点多々あるかと思いますがアドバイスお願いいたします。

回答
投稿日時: 22/10/20 11:04:46
投稿者: taitani
投稿者のウェブサイトに移動

    While TypeName(olItem) = "AppointmentItem"
        If olItem.Start >= strStart And olItem.End < strEnd Then
            With olItem
                Cells(lnContactCount, 2).Value = .Subject
                Cells(lnContactCount + 1, 2).Value = .Body
            End With
            lnContactCount = lnContactCount + 1
        End If
        Set olItem = olConItems.FindNext
    Wend

 
これを、
 
    While TypeName(olItem) = "AppointmentItem"
        If olItem.Start >= strStart And olItem.End < strEnd Then
            With olItem
                Cells(lnContactCount, 1).Value = .Start
                Cells(lnContactCount, 2).Value = .Subject
                Cells(lnContactCount + 1, 2).Value = .Body
            End With
            lnContactCount = lnContactCount + 1
        End If
        Set olItem = olConItems.FindNext
    Wend

 
こんな感じかな?
※すみません、動作確認はしていないです。

回答
投稿日時: 22/10/20 11:12:40
投稿者: taitani
投稿者のウェブサイトに移動

一応、参考になる情報も載せておきますね。
https://extan.jp/?p=1663

回答
投稿日時: 22/10/20 14:01:44
投稿者: sk

引用:
アウトルック予定表に登録されているタイトルと本文を
エクセルシートの該当の日付に転記していきたい

引用:
エクセルシートの該当の日付を探して予定表の内容を転記させる

引用:
strStart = Format("2022/10/1", "yyyy/mm/dd")
strEnd = Format("2022/10/7", "yyyy/mm/dd")

・2022/10/1 から 2022/10/7 までの間に追加されている予定を抽出した上、
 それぞれの予定の日付と同じ値が格納されているセルを検索したい。
 (ヒットするセルがない場合は予定の件名と本文を出力しない)
 
・あるセルに格納されている値を条件として、その値と同じ日付の予定を抽出したい。
 (抽出条件となる日付の範囲をハードコーディングしない)
 
どちらの意味でおっしゃっているのか不明瞭ですが、
とりあえずマクロを実行する前(初期状態)のワークシートの
内容を具体的に明記されることをお奨めします。

回答
投稿日時: 22/10/20 16:00:43
投稿者: simple

動作確認していないので恐縮ですが、メモします。
 
olItem.Start ,olItem.Endの型を調べて下さい。
たぶんDate型だろうと思います(そうでなければ、CDateでDate型に変換します)。
さらにその整数部分(日付部分)だけをとって(最初からCLngでもよいかも)、
シートのA列を対象に、
Application.Matchで検索すれば日付照合は可能です。
(第三引数は0を指定)
 
なお、例示では、
10月3日だけが2件書き込めるように見えますが、
あらかじめ件数が分かるわけはないので、そのあたりが疑問です。
skさんがご指摘のことを私も感じました。
 
・複数件数あれば、右の列に追記するような方式にするか、
・予め日付を書くのはやめて、開始日等自体を書き出す方式にするか
でしょうか。ご検討ください。

投稿日時: 22/10/20 21:00:24
投稿者: miyuukate

みなさまありがとうございます。早速たくさんの方からアドバイスいただき助かります。
 
エクセルシートは下記のようなイメージで先に作成しておかなければならない仕様です。
日付を検索し該当の予定表がある場合のみ転記し、無い場合はそのまま空欄になります。
(ある場合、1日に2件3件となる場合もあり、下方向に転記させる形にしたいのですが、何件あるかはご指摘の通りわからないのでとりあえず2件分の枠を作成しましたが3件以上の場合どう転記させたらいいかも悩んでいます。)
 
 

	A	    B
1		   A社
2	2022/10/1	
3		
4		
5		
6	2022/10/2	
7		
8		
9		
10	2022/10/3	
11		
12		
13		
14	2022/10/4	
15		
16		
17		
18	2022/10/5	
19		
20		
21		
22	2022/10/6	
23		
24		
25		
26	2022/10/7	
27		
28		
29		

 
アドバイスを参考にコードも手直ししてみました。(Date型かどうか調べる方法を検索してみましたが、勉強不足で様々なエラーが出てわかりません…。)
 
Sub Outlookの予定表をエクセルシートへ転記()
    Dim olApp As Outlook.Application
    Dim olNamespace As Outlook.Namespace
    Dim olFolder As Folder
    Dim olConItems As Outlook.Items
    Dim olItem  As AppointmentItem
    
    Dim wbBook As Workbook
    Dim wsSheet As Worksheet
    Dim lnContactCount As Long
    Dim strDummy As String
    
    Set wbBook = ThisWorkbook
    Set wsSheet = wbBook.Worksheets(1)
        
    wsSheet.Activate
    
    Set olApp = New Outlook.Application
    Set olNamespace = olApp.GetNamespace("MAPI")
    Set olFolder = olNamespace.GetDefaultFolder(olFolderCalendar)
    Set olConItems = olFolder.Items
    
    lnContactCount = 2
    
    Dim objAppt As AppointmentItem
    Dim strStart As String
    Dim strEnd As String
    
    strStart = Format("2022/10/01", "yyyy/mm/dd")
    strEnd = Format("2022/10/07", "yyyy/mm/dd")
    strEnd = DateAdd("d", 1, strEnd)
  
  
    Set olItem = olConItems.Find("[End] < """ & strEnd & """ AND [Start] >= """ & strStart & """")
    
    While TypeName(olItem) = "AppointmentItem"
        If olItem.Start >= strStart And olItem.End < strEnd Then
            If Application.Match(strStart, wsSheet.Cells("A2:A30"), 0) Then
            
             With olItem
                Cells(lnContactCount, 1).Value = .Start
                Cells(lnContactCount, 2).Value = .Subject
                Cells(lnContactCount + 1, 2).Value = .Body
             End With
            lnContactCount = lnContactCount + 1
           End If
        End If
        Set olItem = olConItems.FindNext
    Wend
      
    Set olItem = Nothing
    Set olConItems = Nothing
    Set olFolder = Nothing
    Set olNamespace = Nothing
    Set olApp = Nothing
  
End Sub

 
根本的なとこから方法を変更した方がいいのか…それとも自分の知識がないだけで可能なのか…その辺りもアドバイスいただけると助かります。
どうぞよろしくお願いいたします。

回答
投稿日時: 22/10/21 06:49:43
投稿者: simple

前回の発言で書いた方針に沿って、以下の前提でコードを作成してみました。
 
・A列の日付は、行を空けずに連続して書いておき(連続していなくても可)、
・該当する件名と、本文をB列、C列に書き込みます。
・同日に別のデータがあれば、D,E列に追記し、
・さらにデータがあれば、その右に追記する
という前提で、コードを作ってみました。
 
そちらでコードを作成する際の参考にしてください。
 

Sub Outlookの予定表をエクセルシートへ転記()

   Dim olApp As Outlook.Application
   Dim olNamespace As Outlook.Namespace
   Dim olFolder As Folder
   Dim olConItems As Outlook.Items
   Dim olItem As AppointmentItem

   Dim wbBook As Workbook
   Dim ws As Worksheet
   Dim pos As Variant
   Dim strDummy As String

   Set wbBook = ThisWorkbook
   Set ws = wbBook.Worksheets(1)
   ws.Activate

   Set olApp = New Outlook.Application
   Set olNamespace = olApp.GetNamespace("MAPI")
   Set olFolder = olNamespace.GetDefaultFolder(olFolderCalendar)
   Set olConItems = olFolder.Items

   Dim objAppt As AppointmentItem
   Dim strStart As String
   Dim strEnd As String

   strStart = "2022/10/20"         '"yyyy/mm/dd"形式で指定 ■要修正
   strEnd = "2022/10/31"           '■要修正
   strEnd = DateAdd("d", 1, strEnd)  'そのままにしています

   Set olItem = olConItems.Find("[End] < """ & strEnd & """ AND [Start] >= """ & strStart & """")

   While TypeName(olItem) = "AppointmentItem"
      If olItem.Start >= strStart And olItem.End < strEnd Then
         With olItem
            pos = Application.Match(CLng(olItem.Start), ws.Columns(1), 0)
            If Not IsError(pos) Then
              ws.Cells(pos, Columns.Count).End(xlToLeft).Offset(0, 1).Value = .Subject
              ws.Cells(pos, Columns.Count).End(xlToLeft).Offset(0, 1).Value = .Body
            Else
              MsgBox olItem.Start & "の日付がマッチしませんでした"
            End If
         End With
      End If
      Set olItem = olConItems.FindNext
   Wend

   Set olItem = Nothing
   Set olConItems = Nothing
   Set olFolder = Nothing
   Set olNamespace = Nothing
   Set olApp = Nothing
End Sub

なお、失礼ながら、どのような表にするかまで人任せの印象があります。
それをどのような使うのかは、こちらでは分かりません。
その後、何かの集計に使うのか、単なる保存用のものなのか等々。
当事者意識を持って議論を進められたほうがいいですよ。

回答
投稿日時: 22/10/21 10:42:25
投稿者: sk

引用:
エクセルシートは下記のようなイメージで先に作成しておかなければならない仕様です。
日付を検索し該当の予定表がある場合のみ転記し、無い場合はそのまま空欄になります。

引用:
	A	    B
1		   A社
2	2022/10/1	

B1 セルに社名らしき文字列が格納されているようですが、
予定を抽出するに当たって日付以外の条件は特にないのでしょうか。

投稿日時: 22/10/21 22:50:26
投稿者: miyuukate

アドバイスありがとうございます。
日付を選択し、予定表のデータを転記することができました。
またうまく意図が説明できず、色々くみ取っていただきありがとうございます。
 
このコードを参考に下記のような下↓方向に追加していく形の表を毎週作成して保存していくように使用する予定です。
(B1に入ってる社名は転記には関係ないもので検索は日付のみです。)
 
<作成したいエクセル表の形式>

	A	       B
1		       A社
2	2022/10/20	
3		
4		
5		
6	2022/10/21	  会議@
7		     第1会議室
8		
9		
10	2022/10/22	
11		
12		
13		
14	2022/10/23	  会議A
15		     第2会議室
16		      会議B
17		     第3会議室
18	2022/10/24	
19		
20		
21		
22	2022/10/25	  会議B
23		     第4会議室
24		
25		
26	2022/10/26	
27		
28		
29		

 
(会議等の予定は例としていれてあります。)
 
ネックなのが予定が同日に2件以上ある場合に下方向追加だと2件以上の予定がある日付を検索し、行を追加して2件目の予定を転記する点です。
(上記の表だと10月23日は行を追加して2件目の予定を転記するイメージです。)
 
ダイレクトにその形にするのは試行錯誤してますがうまく行かず…
1度別シートに2件以上の予定は右方向に書き出して予定の数を確認し(C列以降→に2件以上〜)、別シートC列、E列(一応3つ予定がある場合)に文字が入ってる場合、完成形のエクセル表の同日の日付を検索し行を追加して転記するという形ではどうかと再考してます。
 
   While TypeName(olItem) = "AppointmentItem"
      If olItem.Start >= strStart And olItem.End < strEnd Then
         With olItem
            pos = Application.Match(CLng(olItem.Start), ws.Columns(1), 0)
            If Not IsError(pos) Then
       ws.Cells[u]([color=red]pos, Columns.Count).End(xlToLeft).Offset(0, 1)[/color][/u].Value = .Subject
              ws.Cells([u][color=red]pos, Columns.Count).End(xlToLeft).Offset(0, 1[/color])[/u].Value = .Body
            Else
              MsgBox olItem.Start & "の日付がマッチしませんでした"
            End If
         End With
      End If
      Set olItem = olConItems.FindNext
   Wend
  
  Dim wb As Workbook
    Dim ws1 As Worksheet
    Dim ws2 As Worksheet
    Set ws1 = ThisWorkbook.Worksheets(1)'右方向に2件目以上を書き出したシート
    Set ws2 = ThisWorkbook.Worksheets(2)'下方向に2件目以上を転記したい完成形のシート
    Dim i As Long
    i = 1
      If ws1.Cells(i, "D") = "" Then Exit Sub '2件以上予定がある場合、D列に転記されている
         If ws1.Cells(i, "D") = 1 Then
             ws2.Cells(i, "C").Insert (xlDown)
             i = i + 1
          End If
        i = i + 1
                  
End Sub

 
行の追加をする場合、エクセル表の該当の日付を検索してそこに追加するのに上記のようなコードも考えてみましたが、これをどのように上記の日付検索(下線の部分など)もどう変更していいかわからないです。
お忙しいとこと何度もすみませんがアドバイスよろしくお願いいたします。
 
 
 
 
 

回答
投稿日時: 22/10/22 19:11:04
投稿者: simple

日ごとの件数が可変で、所要行数があらかじめ定められないのですから、
日付にマッチする方式はやめたほうが楽でしょう。
 
で、どうするかと言えば、

2022/10/22  タイトル
2022/10/22  本文
2022/10/23  タイトル
2022/10/23  本文
2022/10/23  タイトル
2022/10/23  本文
のような形式で上から順次書き込んでいくほうがよいでしょう。
 
(1)予定のない日が表示されないと困る、ということなら下記。
   ・日付範囲の最初から最後までをループで見ていき、
     該当データが無い日があれば、
2022/10/27
2022/10/27

     といった2行のダミーデータを表の最後に追加します。
   ・全体を日付の昇順でソートし直しすればOKです。
 
(2)
2022/10/22  タイトル
2022/10/22  本文
という形式で出力した場合に、同一日付が並ぶのは見てくれが悪い、というなら下記。
条件付き書式を使って、前行と同じ場合は、フォント色を白にする、
(もしくは、表示形式を ;;; に指定する)といった対応をとればいいでしょう。
 
申し訳ないが、私の回答は以上です。頑張ってください。
また、他の方からの回答をお待ちください。

投稿日時: 22/10/22 22:31:30
投稿者: miyuukate

ありがとうございます。
アドバイスを参考にエクセルの表自体を見直したいと思います。
タイトル、本文の2行ごとの方式を試行錯誤してみます。
(必要ない部分の色を白に変えるという発想が自分には思いつかないので勉強になりました。)
 
まだしばらくこの表の完成のために時間を要することになると思いますが、質問の仕方が漠然としていたため、今後はその中でわからない点をピンポイントに絞って質問したいと思います。
 

回答
投稿日時: 22/10/24 10:25:18
投稿者: sk

引用:
B1に入ってる社名は転記には関係ないもので検索は日付のみです。

(標準モジュール)
-----------------------------------------------------------------
Sub OutputAppointsFromOutlook()
On Error GoTo Err_OutputAppointsFromOutlook
  
    Const OutputPropertiesCount As Long = 2
  
    Dim wbBook As Workbook
    Dim wsSheet As Worksheet
    Dim lngDateColumn As Long
    Dim lngContentColumn As Long
    Dim lngFirstDataRow As Long
    Dim lngLastDataRow As Long
      
    Set wbBook = ThisWorkbook
    Set wsSheet = wbBook.Worksheets(1)
      
    With wsSheet
        lngDateColumn = 1
        lngContentColumn = 2
        lngFirstDataRow = 2
        lngLastDataRow = .Cells(.Rows.Count, lngDateColumn).End(xlUp).Row
        If lngFirstDataRow > lngLastDataRow Then
            Set wsSheet = Nothing
            Set wbBook = Nothing
            Exit Sub
        End If
    End With
      
    Dim olApp As Outlook.Application
    Dim blCreateApp As Boolean
      
    blCreateApp = False
    On Error Resume Next
    Set olApp = GetObject(, "Outlook.Application")
    If Err.Number <> 0 Then
        Err.Clear
        On Error GoTo Err_OutputAppointsFromOutlook
        Set olApp = New Outlook.Application
        blCreateApp = True
    End If
    On Error GoTo Err_OutputAppointsFromOutlook
     
    Dim olNamespace As Outlook.Namespace
    Dim olFolder As Outlook.Folder
    Dim olCalenderItems As Outlook.Items
    Dim olAppItem As Outlook.AppointmentItem
     
    Set olNamespace = olApp.GetNamespace("MAPI")
    Set olFolder = olNamespace.GetDefaultFolder(olFolderCalendar)
    Set olCalenderItems = olFolder.Items
     
    Dim rngDate As Range
    Dim rngNextDate As Range
    Dim strStartDate As String
    Dim strEndDate As String
    Dim strFilter As String
    Dim lngContentRow As Long
    Dim lngNextDateRow As Long
    Dim lngInsertRows As Long
    Dim lngInsertStart As Long
    Dim lngInsertEnd As Long
     
    With wsSheet
        Set rngDate = .Cells(lngLastDataRow, lngDateColumn)
        Do
            If IsEmpty(rngDate.Offset(1, 0).Value) = False Then
                Set rngNextDate = rngDate.Offset(1, 0)
            Else
                Set rngNextDate = rngDate.End(xlDown)
            End If
            If IsDate(rngDate.Value) Then
                lngContentRow = rngDate.Row
                strStartDate = Format(rngDate.Value, "ddddd h:nn AMPM")
                strEndDate = Format(DateAdd("d", 1, strStartDate), "ddddd h:nn AMPM")
                strFilter = "[Start] >= """ & strStartDate & """ AND [Start] < """ & strEndDate & """"
                Set olAppItem = olCalenderItems.Find(strFilter)
                Do Until olAppItem Is Nothing
                    lngNextDateRow = rngNextDate.Row
                    If (lngNextDateRow - lngContentRow) < OutputPropertiesCount Then
                        lngInsertRows = OutputPropertiesCount - (lngNextDateRow - lngContentRow)
                        lngInsertStart = lngNextDateRow
                        lngInsertEnd = lngInsertStart + lngInsertRows - 1
                        .Range(lngInsertStart & ":" & lngInsertEnd).EntireRow.Insert
                    End If
                    .Cells(lngContentRow, lngContentColumn).Value = olAppItem.Subject
                    .Cells(lngContentRow + 1, lngContentColumn).Value = olAppItem.Body
                    lngContentRow = lngContentRow + OutputPropertiesCount
                    Set olAppItem = olCalenderItems.FindNext
                Loop
            End If
            If IsEmpty(rngDate.Offset(-1, 0).Value) = False Then
                Set rngDate = rngDate.Offset(-1, 0)
            Else
                Set rngDate = rngDate.End(xlUp)
            End If
        Loop Until rngDate.Row < lngFirstDataRow
    End With
     
Exit_OutputAppointsFromOutlook:
On Error Resume Next
     
    Set olAppItem = Nothing
    Set olCalenderItems = Nothing
    Set olFolder = Nothing
    Set olNamespace = Nothing
    If blCreateApp Then
        olApp.Quit
    End If
    Set olApp = Nothing
     
    Exit Sub
     
Err_OutputAppointsFromOutlook:
     
    MsgBox Err.Number & ": " & Err.Description, _
           vbCritical, _
           "実行時エラー(OutputAppointsFromOutlook)"
          
    Resume Exit_OutputAppointsFromOutlook
End Sub
-----------------------------------------------------------------
 
以上のようなコードを実行なさればよろしいのではないかと。
 
引用:
このコードを参考に下記のような下↓方向に追加していく形の表を
毎週作成して保存していくように使用する予定です。

但し、既にいずれかの日の予定の件名や本文が
ワークシート上に書き込まれている場合については
考慮していません。

投稿日時: 22/10/24 21:53:43
投稿者: miyuukate

ありがとうございます!
希望していた形式に作成することができました。
まずは取り急ぎお礼申し上げます。
これから一つ一つ構文を解析して勉強していきたいと思います。
 
掲示板の皆さまから色々なアドバイスをいただき、とても勉強になりました。
ありがとうございました。