0
votes

So I'm working on automating a tedious process that uncle sam makes us do while deployed. I have a database where we put in a date for each day we are deployed into a table. For instance I have 4/10/2017 through 7/11/2017 listed. Each day needs the date and location displayed and I need to put six results stacked vertically then move to the right to do the next six three more times.

I have one report named 2282report which is the master one with four subLocation[1-4]s in the appropriate spot. Originally I had it do TOP 6 then the next one would do TOP 6 but where ID > 6 but then I moved to make the date the ID as the date can't be duplicated anyway. I'm unsure of the proper way to make them linked so that the next subreport will display continue the rest.

The report looks like this when ran. I will also have over 90 days usually to list so I will need to create a second page to the main report.

Print Preview

What I'm thinking I'll have to do is create a new subreport for the entire location block but I don't know how to make the report_details move to a new column once it shows 6 results.

Another option I just thought of is to leave the subreports blank then make the master report set the controlsource for each one via vba. I feel this one may work because then it can check to see if there are more days then there are lines so that it can create a new page to continue. But then I need to figure out how to make it continue to the next page. There will also be a bottom section that will only have 16 days versus the 24 on the top.

Design View

1
Why does your example show 20170408 - 20170413 twice? Just an oversight in building the example? Why only 6 lines? Doesn't that leave a lot of unused white space on the sheet? Can you provide the database for analysis and testing? I recommend Box.com fileshare site and post link to file. - June7
One suggestion: You could create a multi-column report to at least handle the four columns. This still leaves the task of continuing the report between pages, but at least reduces the amount of work for the columns. For Access 2013, go to Report Design , then to the Page Setup ribbon and click the Columns icon for various options. - C Perkins
Regarding the final page with 16 instead of 24, is that an absolute given? Is this true even if the number of sub-report rows has an exact multiple of 24? In that case, would that leave the 16 entries blank on the last page, or does this need to balance the number of entries so that no page has a completely blank sub-report? Regardless of the your particular solution, I'm guessing that will require creating a separate report altogether just for the last page. - C Perkins

1 Answers

1
votes

You might be tempted to use VBA in the various report event handlers, but even if this might work, from my experience that would only lead to headaches trying to get everything to format properly. Instead, I recommend creating a new reporting table with a page number on each row. Source the main report from the sorted page number list and bind a multi-column subreport via the page number field. Populate the reporting table with a simple VBA procedure that correctly paginates the rows according to your scheme.

First the reporting table (add constraints as you find necessary):

CREATE TABLE SubReportTable (PageNum LONG, PageOrdinal LONG, _
    Ordinal LONG, LastPage BIT, [Date of Service] DATE,  [Location] TEXT)

On the SubReport:

  • Set RecordSoucre property: SubReportTable (alternatively specify a query that sorts on the desired fields)
  • Set Number of Columns to 4 along with other column settings (padding, direction, etc.).
  • Set CanGrow property to No on Detail section and other controls as appropriate.
  • Resize columns and detail section to properly fit all columns on page. (This will likely require going back and forth between print preview and design on the Main Form.)

On the main report, set the following properties:

  • RecordSource property: SELECT SubReportTable.PageNum FROM SubReportTable WHERE (((SubReportTable.LastPage)=False)) GROUP BY SubReportTable.PageNum ORDER BY SubReportTable.PageNum
  • Detail section property Force New Page to After Section.
  • SubReport object's Link Master Fields and Link Child Fields both to PageNum
  • Resize SubReport object to fit all columns properly.

Duplicate the behavior on the Main Report on a separate "Last Page" report. Set this report to select the proper subset of records based on the pagination data in the reporting table (i.e. LastPage = True). Depending on how different the last page with 16 records is formatted, it might also require creating a separate SubReport just for the 16 records, but you might get away with using the same SubReport as the main report... that'll be your problem to determine.

  • RecordSource property: SELECT SubReportTable.PageNum FROM SubReportTable WHERE ((SubReportTable.LastPage = True)) GROUP BY SubReportTable.PageNum ORDER BY SubReportTable.PageNum

Finally some code to populate the reporting table. You can either run this procedure directly from the VBA Immediate Window, or put it in some button's click event handler. The pagination logic can be tweaked to get the right amount of records on the last page.

Public Sub PrepareSubReporTable()
  On Error GoTo Catch_PrepareSubReporTable

  Dim db As Database
  Dim rs As Recordset2
  Dim rows As Long, pgs24 As Long, rowsLast24 As Long, rows16 As Long
  Dim i As Long, p As Long, pi As Long

  Set db = CurrentDb

  db.Execute "DELETE * FROM [SubReportTable]", dbFailOnError

  db.Execute _
    "INSERT INTO SubReportTable ( PageNum, PageOrdinal, Ordinal, LastPage, [Date of Service], [Location] )" & _
    " SELECT Null AS PageNum, Null AS PageOrdinal, Null AS Ordinal, False as LastPage," & _
        " [Data].[Date of Service], [Data].[Location]" & _
    " FROM [Data]" & _
    " ORDER BY [Data].[Date of Service], [Data].[Location];", _
    dbFailOnError

  rows = db.OpenRecordset("SELECT Count(*) FROM SubReportTable").Fields(0)
  pgs24 = rows \ 24
  rows16 = rows - 24 * pgs24
  If rows16 > 16 Then
    rowsLast24 = rows16
    pgs24 = pgs24 + 1
    rows16 = 0
  Else
    rowsLast24 = 24
  End If

  Set rs = db.OpenRecordset( _
      "SELECT * FROM SubReportTable" & _
      " ORDER BY [Date of Service], [Location];")
  i = 0
  Do Until rs.EOF
    p = i \ 24 + 1

    rs.Edit
    rs![PageNum] = p
    If p > pgs24 Then
      rs![lastPage] = True
      pi = (i - pgs24 * 24) Mod 16 + 1
    Else
      pi = i Mod 24 + 1
    End If
    rs![PageOrdinal] = pi
    i = i + 1
    rs![Ordinal] = i
    rs.Update

    rs.MoveNext
  Loop
  rs.Close

  Exit Sub
Catch_PrepareSubReporTable:
  MsgBox Err.Number & ": " & Err.Description, _
      vbOKOnly Or vbExclamation, "Error in PrepareSubReporTable"
End Sub

Now generate the main report and the last-page report, either manually or in VBA code somewhere.

Note: I used the field name PageNum instead of Page because that seemed to cause problems with a SubReport binding during print preview... probably because Page is the name of an existing variable / function for reports.