如何获取 Word 邮件合并文档中包含的记录列表?

How can get a list of included records in a Word Mail Merge Document?

我有一个通过 VBA 控制的邮件合并文档。在用户 selects 他想要打印的记录之后,我希望这些记录在数据库中设置打印日期。为此,我需要邮件合并中包含的记录列表。

我尝试使用 .Included property,设置 ThisDocument.MailMerge.DataSource.ActiveRecord = wdFirstRecord(我后来删除了 wdFirstRecord 以支持 1,因为它给我带来了麻烦) 然后检查 ThisDocument.MailMerge.DataSource.Included 是否为真,但出现 5852 运行时错误 "Object not available"。 编辑: 我使用以下代码遍历记录。当我删除任何一个评论的 .Included 语句时,我得到了错误。 (执行感觉不像昨天那么慢了,虽然不是特别快。)

Function outputRecords(Optional limitRecords = -1)
    With ThisDocument.MailMerge.DataSource
    Dim str
        For currentFieldNameIndex = 1 To .FieldNames.Count
            str = str & .FieldNames(currentFieldNameIndex) & vbTab
        Next
        Debug.Print str

        For currentRecordIndex = 1 To .RecordCount
            If currentRecordIndex <= limitRecords Or limitRecords < 0 Then
                .ActiveRecord = currentRecordIndex
                str = ""
                For currentDataFieldIndex = 1 To .DataFields.Count
                    str = str & .DataFields(currentDataFieldIndex) & vbTab
                Next
                'Debug.Print str
            End If
            '.Included = True
            'Debug.Print .Included
        Next

    End With
End Function

是否有解决方案可以知道用户 select编辑了哪些记录?

关于我的文档:经过一些一般计算,数据源链接到文档使用

Dim sql As String
sql = "SELECT * FROM `Sheet0$` "
sql = sql & "WHERE ((`" & photoPathHeader & "` > '') AND (`" & photoLastEditHeader & "` >= #" & Format(printFromDate, "yyyy-mm-dd") & "#)) "
sql = sql & "ORDER BY `klasse#name` ASC"
ThisDocument.MailMerge.OpenDataSource _
    name:=ThisDocument.Path & "\" & ThisDocument.Variables("masterDataFileName"), _
    SQLStatement1:=sql, _
    ReadOnly:=True, LinkToSource:=True

显示一个对话框,用户可以在其中 select 打印单个记录。我为此使用了这段代码:

Application.Dialogs(wdDialogMailMergeRecipients).Display

最后,使用

执行邮件合并
ThisDocument.MailMerge.Execute

非常感谢!

此答案基于目前的评论。

  1. 我不明白 .Included here 的问题,除非 ThisDocument 是错误的文档。但是,由于您的循环代码在访问 ThisDocument.MailMerge.DataSource 的其他成员时似乎没有抛出错误,因此问题不明显。但是,我认为您不需要使用 .Included.
  2. 当我尝试访问任何 .Datasource.DataFields 项目时,我立即发现速度变慢了。我不知道为什么会这样。每次访问都有延迟,而不仅仅是每条记录的第一次访问。我的一个想法是,一旦您更改活动记录,Word 就会刷新主文档中合并字段的值,这可能会导致问题,特别是如果 Word 出于某种原因需要访问打印机驱动程序时。但我没有尝试(例如将视图更改为草稿)改变这一点。
  3. 你真的不需要 .Included 因为你可以像这样迭代记录:

    With ActiveDocument.MailMerge.DataSource
      previousRecord = 0
      .ActiveRecord = wdFirstRecord
      While .ActiveRecord <> previousRecord
        previousRecord = .ActiveRecord
        Debug.Print .ActiveRecord ' (just lists the record number)
        previousRecord = .ActiveRecord
        .ActiveRecord = wdNextRecord
        DoEvents ' advisable if you need to stop the code
      Wend
    

    如果您需要迭代所有记录,那么您需要改用wdFirstDataSourceRecord和wdNextDataSourceRecord。

  4. 我能够加快访问数据的唯一方法是修改文档以包含我想列出的所有字段,然后从文档而不是从 .DataSource.Datafields。我个人认为修改 Mail Merge 主文档并不理想——特别是,有些东西可能会阻止您在开头插入 material,就像我所做的那样。但是我的测试代码(需要更多错误捕获等)是这样的:

    Sub checkincluded()
    Dim b As Word.Bookmark
    Dim bVMMFC As Boolean
    Dim bSFC As Boolean
    Dim i As Integer
    Dim previousRecord As Long
    Dim p As Word.Paragraph
    Dim r As Word.Range
    
    With ActiveWindow.View
      bSFC = .ShowFieldCodes
      .ShowFieldCodes = False
    End With
    
    With ActiveDocument.MailMerge
      bVMMFC = .ViewMailMergeFieldCodes
      .ViewMailMergeFieldCodes = False
    
      With .DataSource
        Set r = ActiveDocument.Range(0, 0)
        Set p = ActiveDocument.Range(0, 0).Paragraphs.Add
    
    
        For i = 1 To .FieldNames.Count
          If i > 1 Then
            r.Text = vbTab
            r.Start = p.Range.End - 1
            r.End = p.Range.End - 1
          End If
          r.Fields.Add r, WdFieldType.wdFieldMergeField, .FieldNames(i), False
          r.Start = p.Range.End - 1
          r.End = p.Range.End - 1
        Next
        r.Start = 0
        r.End = p.Range.End - 1
        Set b = r.Bookmarks.Add("recorddata")
        Set r = Nothing
    
        previousRecord = 0
        .ActiveRecord = wdFirstRecord
        While .ActiveRecord <> previousRecord
          previousRecord = .ActiveRecord
          Debug.Print .ActiveRecord, b.Range.Text
          previousRecord = .ActiveRecord
          .ActiveRecord = wdNextRecord
          DoEvents
        Wend
        b.Delete
        Set b = Nothing
        p.Range.Text = ""
        Set p = Nothing
      End With
      .ViewMailMergeFieldCodes = bVMMFC
    End With
    
    ActiveWindow.View.ShowFieldCodes = bSFC
    
    End Sub
    
  5. 最后,可能值得指出的是,还有其他方法可以排除记录,例如使用 NEXT、NEXTIF、SKIP 和 SKIPIF 字段。但这也许是另一个问题。

感谢@yokki 的回答,我能够将其与我所知道的结合起来并得到以下结果

Sub listIncluded()
    Dim LastRecord As Long
    With ActiveDocument.MailMerge.DataSource

    ' Storing the index of the last record for later use
    .ActiveRecord = wdLastRecord
    LastRecord = .ActiveRecord

    .ActiveRecord = wdFirstRecord
        Do
            Debug.Print .ActiveRecord
            DoEvents
            If .ActiveRecord = LastRecord Then Exit Do
            .ActiveRecord = wdNextRecord
        Loop Until .ActiveRecord > LastRecord ' Note this will never be satisfied and the loop will always be exited via the Exit Do statement
    End With
End Sub

我发现 WdMailMergeActiveRecord enumeration 有点令人困惑,但它有效。

如果最后一个包含的记录已经到达并且不等于最后一个记录整体(即不包括最后一个记录),则原始答案在 wdNextRecord 上抛出 5853 Invalid parameter 错误.我通过将最后一条记录的索引存储到局部变量中并使用它来检查是否到达了最后一条包含的记录来规避了这个问题。

非常感谢大家的帮助!

正如评论中简要指出的那样,我已经列出了所有 数据源中的数据作为数组,因为我也在其他部分使用它 的脚本。我为此使用了以下语句

numRows = wks.Range("A1").CurrentRegion.Rows.Count
masterData = wks.Range("A1").CurrentRegion.Offset(RowOffset:=1).Resize(RowSize:=numRows).Value

wks 引用了一个 Excel 工作表对象。