4.1 · Subreports (linked & unlinked)

Level 4 · Expert: subreports, charts & multi-source

4.1Subreports (linked & unlinked)

Goal: Insert a subreport (linked or unlinked), define the link field and master its cost.
Estimated time: 11 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • A subreport = a complete report inside the main one: its own source, fields, formatting — the solution when a simple join is not enough (different sources, multiple one-to-many relationships).
  • Linked or unlinked changes everything: unlinked = the same data shown once (global recap); linked = matching data per link field, re-executed for each main-report value.
  • Farès's reflex: place a linked subreport at group level (one execution per group), never in the Details of a large report — and prefer the join when the tables are in the same database.

Threaded mini-case — Farès and the customer statement with invoices

Farès, a controller in Algiers, must produce the monthly customer statement: the main report lists customers from the management database, but the detailed invoices come from another extract that a join would inflate with duplicates (two one-to-many relationships: orders AND payments). He inserts a subreport linked on customer ID, placed in the Customer group header: for each customer, the subreport shows THAT customer's invoices, a single execution per customer. First milestone of the thread: Farès combines two sources without duplicates and without killing performance.

This same case returns in the lesson, the diagram, the script and the 48h challenge — and continues in 4.2, 4.3, 4.4 and 4.5.

1. A report inside a report: when the subreport is required

Level 4 opens the expert features. First among them: subreports — a complete report (its own source, fields, formatting) inserted into a section of the “main” report. As with Farès's statement, its strength is combining data that does NOT lend itself to a simple join: different sources (two databases, a database + a file), complex or multiple one-to-many relationships that would create duplicates, related information to present separately (for each customer, their latest invoices).

Decision rule: when the tables are in the same database and link cleanly through a key, a join remains simpler and faster — it is the default choice. The subreport is the tool for cases where the join is unsuitable: non-joinable sources, join duplicates, independent logic or aggregation. Insert it via “Insert → Subreport” (new report or import of an existing one), then define the links.

2. Linked vs unlinked: the link field does everything

Key distinction. An unlinked subreport is independent: it shows the same data wherever it sits — for example a global summary shown once in a report footer. A linked subreport is connected to the main report by a link field: for each main-report record or group, it shows the matching data — the orders of THIS customer, like each of Farès's customers' invoices.

Mechanism: in the “Links” step (Subreport Links), choose the main-report field (e.g. Customer.ID); Crystal Reports creates a parameter in the subreport and binds it to the matching field (e.g. Invoices.CustomerID) — the filter applies automatically, ideally server-side. The link field must exist on both sides. Classic pitfall: forgetting the link — the subreport then shows all its data, like an unlinked one.

3. Performance: placement decides the cost

A linked subreport re-executes for each link value of the main report. Placed in the Details section, it runs once PER row — disastrous on large volumes. Placed in a group header or footer, it runs only once per group — this is Farès's move: one execution per customer instead of one per invoice.

Further precautions: limit the subreport's data (server-side filter, useful fields only), avoid nested subreports (multiplied cost), consider an alternative (join, SQL command in 4.4, consolidated view) and test on a real volume. Subreports share data with the main report only with difficulty (shared variables = advanced).

Common misinterpretation: “A subreport is just a visual join: I drop it into Details and it follows on its own.” No. Without a link field defined on both sides, the subreport shows all its data without matching the record; and in Details, a linked subreport executes once per row — the report becomes unusable on large volumes. Link by a common key, filter server-side, place at group level: this trio is what makes a correct subreport.
Subreport: linked or not, and at what cost Matching and cost Unlinked Same data,shown onceLinked Link field:matching dataPlace at group level Oneexecution per groupLimit and test Serverfilter, real volume
Matching and cost
Text version of the diagram (SEO / screen readers / translation): 1) Farès lists customers in the main report (grouped by customer) and reserves joins for tables in the same database. 2) He inserts a subreport on invoices via Insert → Subreport and links it by customer ID (field present on both sides, server-side filter). 3) He places the linked subreport in the Customer group header: one execution per customer, not one per row. 4) He limits the subreport's fields and tests on the real monthly volume. Lesson: link by a common key, place at the group, limit — never a linked subreport in the Details of a large report.

🔎 Concrete example — 🔎 Concrete example — Each customer's invoices

Farès's statement: a customers main report, a linked and well-placed invoices subreport.

Main report: customer list (grouped by customer).
Subreport linked on customer ID → THIS customer's invoices.
Placed in the GROUP HEADER (one execution per customer, not per row).

Reading: link by the common key, filter server-side, place at group level.

Lesson: related data in context, without duplicates or performance collapse.

Section vocabulary

Subreport
A COMPLETE report inserted into another (the main one): its own source, fields, formatting, displayed in a section of the main report.

Simple example: Farès shows invoices (another extract) in the customer statement without joining them.

What it is not: a mere extra section of the same report.

Reflex: non-joinable sources or join duplicates: think subreport.

Linked subreport
Connected to the main report by a LINK FIELD: shows the data matching each record or group, re-executed per link value.

Simple example: For each of Farès's customers, the subreport shows THAT customer's invoices.

What it is not: a global recap identical everywhere.

Reflex: matching data per record: define the link on both sides.

Unlinked subreport
Independent: shows the SAME data wherever it sits in the main report.

Simple example: Farès shows a global recap of unpaid invoices once in a report footer.

What it is not: a detail that follows each record.

Reflex: global recap shown once: unlinked in a report footer.

Cost per execution
A linked subreport executes once PER link value: Details = once per row (expensive), group = once per group.

Simple example: Farès goes from hundreds of executions (Details) to one per customer (group).

What it is not: a fixed cost independent of placement.

Reflex: linked + large volume: always move up to group level.

In practice — In practice — Insert a subreport

  1. Insert a subreport (“Insert → Subreport”): create a new report or import an existing one, with its own source and fields.
  2. Decide LINKED or UNLINKED: unlinked for a global recap (same data); linked for matching data per record or group.
  3. For a LINKED subreport, define the LINK FIELD (e.g. customer ID): it will show the data matching each main-report value.
  4. For PERFORMANCE, place a linked subreport in a GROUP header or footer (once per group) rather than in Details (once per row).
You insert subreports (linked or unlinked) to combine different sources and complex relationships, while mastering the performance impact.

Ready-to-say script — justify the subreport to your manager (30 s)

“This is Farès: for the customer statement, I cannot join the invoices without creating duplicates — so I used a subreport linked by customer ID, placed at group level. One execution per customer instead of one per row: the statement stays accurate and opens in seconds.”

Say when asked why not “simply join”: show the total inflated by duplicates.

Copy-paste template — subreport scoping sheet

Need: [customer statement + invoices from another extract]
Choice: [join impossible → subreport]
Type: [linked on customer ID | unlinked — global recap]
Link: main [Client.ID] → subreport [Factures.ClientID], server-side filter [yes]
Placement: [Customer group header — one execution per customer]
Content: [useful fields only: invoice no., date, amount]

Multi-source customer statement

Like Farès: main report on the management database, subreport linked on the other extract — one execution per customer.

Double one-to-many relationship

A customer's orders AND payments: one subreport per relationship to avoid row multiplication.

Global recap

Total unpaid shown once in a report footer: unlinked subreport, no link field.

Slow large volume

Move the subreport up to the group, filter server-side, consider a SQL command or a view (see 4.4).

✓ Best practices

  • Place a linked subreport at GROUP level, not in Details.
  • Filter the subreport server-side and include only useful fields.
  • Prefer a join when the tables are in the same database.

✗ Common pitfalls

  • A linked subreport in the Details of a large report (disastrous performance).
  • Forgetting the link (the subreport then shows all its data).
  • Chaining nested subreports (multiplied cost).

Key takeaways

  • A SUBREPORT is a COMPLETE report inserted into another. Strength: combining hard-to-JOIN data — different sources, complex relationships, related information.
  • KEY distinction: LINKED (link field — matching data per record/group) vs UNLINKED (independent, same data).
  • PERFORMANCE: a linked one executes once PER link value. Details = very expensive; GROUP header/footer = far fewer executions.
  • Insert via “Insert → Subreport” then define the LINKS. Test on a real volume.

48h challenge — apply tomorrow

On a real statement: insert a linked subreport (common key on both sides), place it at group level, limit its fields and compare the opening time with a placement in Details.

Section exit checklist
  • I can insert a subreport and choose linked or unlinked as needed.
  • I can define a link field present on both sides, filtered server-side.
  • I place a linked subreport at group level and test on a real volume.
Self-rating 1-5: does my last linked subreport execute once per group or per row?did I check that the link field exists on both sides?

Frequently asked questions

When should I use a subreport instead of a join, and how do I avoid performance problems?

When the tables are in the SAME database and link cleanly through a key, a JOIN is simpler and faster — it is the default choice. Reserve the SUBREPORT for cases where the join is unsuitable: DIFFERENT non-joinable sources, multiple one-to-many relationships that would create duplicates, related data to present separately. Performance: a linked subreport re-executes for each link value — NEVER place it in the Details of a large report: put it in a GROUP header or footer, limit its data (server-side filter, useful fields), avoid nested subreports, consider a SQL command or a view (see 4.4), and test on a real volume.

How do I match a subreport's data to each main-report record?

By LINKING the subreport to the main report through a common FIELD (e.g. customer ID). For each main-report record or group, the main report passes a link value and the subreport filters its data on it. In practice: insert the subreport, then in the “Links” step choose the main-report field (Client.ID) and bind it to the matching subreport field (Factures.ClientID) — Crystal Reports creates the parameter and applies the filter automatically. Key points: key present on BOTH sides, server-side filter, placement (Details or group) that sets the execution frequency. Without a link, the subreport shows all its data.

Check your understanding

Where should a linked subreport be placed to preserve performance?

Additional resources (optional, to go further)

Level 4 examFresh, harder questions to test what you've learned