Chapter 12: Audit Analytics in SQL

Accounting Analytics: An Integrated Approach

In this chapter

Part III of V: Accounting Analytics with SQL

Chapter 4 of 4 in this Part

  • 12.1 From Samples to Populations
  • 12.2 Reconciling and Profiling Before Testing
  • 12.3 Tracing in Both Directions
  • Guided Tutorial 12.1
  • 12.5 The Three-Way Match
  • 12.6 Testing Approvals Across a Process
  • Guided Tutorial 12.2
  • 12.8 Testing the Records Behind a Cost
  • Guided Tutorial 12.3
  • 12.10 Chapter 8’s Tests in SQL
  • 12.11 A Library of Audit Queries
  • 12.12 Looking Ahead

Learning objectives

  1. Reconcile a population to the general ledger and profile it in SQL before testing it, and explain what a reconciliation can and cannot show.
  2. Trace ledger postings to their source documents and documents to the ledger with anti-joins, combine the tests into one list of exceptions, and test cutoff with the dates of the events behind revenue and payroll.
  3. Perform a three-way match of purchase orders, goods receipts, and supplier invoices, summing quantities to the purchase order line and applying a price tolerance.

Learning objectives (continued)

  1. Test approvals across a business process against each approver’s limit, role, and employment dates, and measure how concentrated they are.
  2. Test the time, labor, payroll, and payment records behind a cost as one reconciled chain, recalculate the pay from the hours and rates, recognize patterns that the records cannot explain, and judge what the exceptions support.
  3. Organize audit queries into a documented library that can be rerun each period.

Can the records behind the explanation be trusted?

  • You are back on Chapter 8’s internal audit team, testing a colleague’s analysis
  • The plant recorded about half as many hours again as its output’s standard
  • Were the hours worked, approved, charged to the right work, and paid?
  • And why does indirect time almost vanish for four months of the first year?

12.1 From Samples to Populations

SQL tests whole processes, not one table

  • A test can follow a purchase or a labor hour across five or six tables
  • A sample estimates an error rate; a population test finds the actual items
  • Each item found needs a disposition, the auditor’s conclusion about it
  • An incomplete table can report a clean result that means nothing

12.2 Reconciling and Profiling Before Testing

Reconcile and profile before any test

  • A reconciliation is two aggregates: the document table and the ledger
  • They should agree to the cent; a difference is the first finding
  • A profile says what the population holds: its records, keys and dates
  • And how many records are incomplete or unapproved from the start

A reconciliation cannot find what both records omit

  • It compares two records, so it misses what both of them left out
  • Ledger and payroll registers both record wages on the day they are paid
  • So they agree to the cent, even when the last weeks’ wages are in neither
  • Tutorial 12.1 meets that limit at each year-end

12.3 Tracing in Both Directions

Trace both ways between the ledger and documents

Detail of the diagram of the two traces, without the cutoff box. The GLEntry table, with its SourceDocumentType and SourceDocumentID columns, is on the left, and four source document tables, SalesInvoice, PurchaseInvoice, DisbursementPayment and PayrollPayment, are on the right. A dashed amber arrow runs from the ledger through a box on existence to the documents, and a second runs from the documents through a box on completeness back to the ledger. The existence box finds postings whose document key is NULL, and the completeness box finds documents with no GLEntryID.
Figure 12.1 · Tracing in Both Directions Between the Ledger and Its Documents (detail)

Restrict the ledger rows to the document type, then match the document ID.

UNION ALL lists every test’s exceptions together

SELECT 'Posting with no payment' AS Test, ...
FROM GLEntry LEFT JOIN PayrollPayment ...
UNION ALL
SELECT 'Invoice with no posting', ...
FROM SalesInvoice LEFT JOIN GLEntry ...
  • Each query is the anti-join for one kind of document, labeled with its test
  • UNION without ALL also removes duplicate rows, rarely what a list wants

Watch out: UNION ALL matches columns by position

  • Columns are matched by position, not by name
  • The result takes its column names from the first query
  • Columns in another order stack their values under the wrong headings
  • ORDER BY sorts the combined result, so it goes once, at the end

Cutoff compares the posting with the event behind it

  • PostingDate says when it was recorded; the event has its own date
  • Revenue on delivery, as the chapter assumes: compare the delivery dates
  • An invoice dated before its goods shipped needs correction or a reason
  • Wages belong to the period of the work: compare the work with the pay date

Check your understanding

Which test finds each problem?

  1. A ledger posting whose document does not exist
  2. A supplier invoice that was never posted
  3. Revenue posted in January for goods delivered in December
  4. A sale for which no document was ever created

Each problem has its test

  1. Existence: an anti-join from the ledger to the documents
  2. Completeness: an anti-join from the documents to the ledger
  3. Cutoff: the posting date against the delivery date
  4. No trace finds it: there is no record to join

Guided Tutorial 12.1: Reconciling the Populations, Tracing the Ledger, and Testing Cutoff

Reconcile, trace and test cutoff in eight steps

  1. Reconcile the journal entries to the ledger
  2. Reconcile the manufacturing payroll to the ledger
  3. List the trace exceptions in both directions
  4. Explain the six postings
  5. Test the cutoff of revenue
  6. Find the shipments never invoiced
  7. List the pay periods that cross a year-end
  8. Look for an accrual of the unpaid wages

Six postings point to no payment

Detail of the result grid of the combined trace test, six rows with the columns Test, RecordID, DocumentID, RecordDate and Amount. Every row reads Posting with no payroll payment, in the outlined Test column. The rows come in three pairs of equal amounts, dated in January 2024, January 2025 and January 2026, and the two rows of each pair share a DocumentID.
Figure 12.2 · The Trace Exceptions in One List (detail)

December deliveries were posted in January

Detail of the result grid of the revenue cutoff test, five rows with the columns Finding, DeliveryYear, Invoices and SubTotal. Three rows are invoices dated before shipment, one for each year from 2024 to 2026. The two outlined rows are revenue posted in another year, for deliveries of 2024 and of 2025, the first with more invoices than the second.
Figure 12.3 · Revenue Posted Outside the Year of Delivery (detail)

Checkpoint

Check that:

  • the journal entries and the manufacturing payroll reconcile to the ledger to the cent;
  • the combined trace returns six postings with no payroll payment and nothing else;
  • the six postings match three approved registers without payments, two of them for a terminated employee, charged to the Executive cost center;

Checkpoint (continued)

  • the revenue of December deliveries posted in January fell in the next fiscal year, and a few December 2026 shipments were never invoiced;
  • account 2030 holds only its opening balance, with no accrual of the wages of late December;
  • Audit.sql holds the header and the eight tests of this tutorial, each under its comment.

12.5 The Three-Way Match

Sum each side to the purchase order line

Detail of the diagram of the three-way match for one purchase order line, without the table of statuses below it. The line is at the top with its ordered quantity and unit cost. On the left, its two goods receipt lines are summed into the quantity received. On the right, its three supplier invoice lines, each with its price compared with the order price, are summed into the quantity invoiced. The three quantities are equal, so the line is matched, although one receipt line is billed on two invoice lines.
Figure 12.4 · The Three-Way Match at the Level of the Purchase Order Line (detail)

Each line ends in one status

Detail of the table of the statuses of a purchase order line, in the order the CASE tests them, with each condition and meaning. The first two rows, outlined, are the exceptions, invoiced above received and received above ordered. Below them come not yet received, received not fully invoiced, which is an accrual, partly received and matched. A note under the table says that compared row by row a receipt line matches neither of its invoice lines, but summed to the purchase order line the quantities agree.
Figure 12.4 · The Three-Way Match at the Level of the Purchase Order Line (detail)

Tolerances, prices and unbilled receipts

  • Quantities are REAL, so two sums are equal within a tiny tolerance
  • Some price difference is normal: the purchase price variance records it
  • A tolerance, such as two or three percent, separates the exceptions
  • Goods received but not invoiced are a liability to agree with the ledger

12.6 Testing Approvals Across a Process

Was each approver entitled to approve?

  • Join each document to its approver’s Employee row
  • An amount above MaxApprovalAmount is an approval above authority
  • One dated after TerminationDate may have come from someone who had left
  • A creator who also approves breaks the segregation of duties

Concentration is a risk, not an exception

  • Approval tests look for a few exceptions in a large population
  • They often return a clean result, and that is evidence too
  • Provided the population was reconciled first
  • If one person approves nearly everything, the control rests on one review

Check your understanding

Exception, accrual or risk?

  1. A split receipt: ordered, received and invoiced quantities agree when summed at the order line
  2. Goods received at the year-end that the supplier has not yet billed
  3. A purchase order above its approver’s limit
  4. One person approves nearly every purchase order

Each finding has its meaning

  1. No quantity exception: the summed quantities agree at the purchase order line
  2. An accrual: a liability to agree with the ledger
  3. An exception: an approval above authority
  4. A risk: a possible weakness in the control’s design

Guided Tutorial 12.2: Matching Purchases and Testing Their Approvals

Match and test the approvals in six steps

  1. Match every purchase order line
  2. Test prices against two tolerances
  3. Reconcile the goods received but not invoiced
  4. Test the approvals of the purchase orders
  5. List the orders behind the exceptions
  6. Measure the concentration of approvals

No line was billed or received beyond its order

Detail of the result grid of the three-way match, four rows with the columns MatchStatus and POLines. Matched holds the great majority of lines, followed by Received, not fully invoiced, Not yet received and Partly received. No exception status appears, and the whole grid is outlined.
Figure 12.5 · The Three-Way Match of Every Purchase Order Line (detail)

A handful of orders fail the approval tests

Detail of the result grid of the approval tests on purchase orders, three rows with the columns Test, Orders and OrderValue. The tests are Above approver limit, Self-approved and Dated after approver left, with between three and thirteen orders each and their total values. The grid is outlined.
Figure 12.6 · Approval Exceptions in the Purchase Orders (detail)

Checkpoint

Check that:

  • the three-way match reports no line invoiced above received or received above ordered;
  • no invoice price differs from its order price by more than three percent;
  • the receipts not yet invoiced agree with account 2020 to within a dollar;
  • the approval tests flag fourteen orders, among them two large self-approved orders and three dated after their approver’s termination, and one person approved almost all the others;
  • Audit.sql holds this tutorial’s six tests under their comments.

12.8 Testing the Records Behind a Cost

The chain of records behind the labor cost

A chain of five boxes from left to right: time clock entry, labor time entry, payroll register, payroll payment, and general ledger, each naming the key that links it to the record before it; the payroll register is linked to the labor time through the earnings lines of PayrollRegisterLine. The last link, a posting to the ledger, is dashed. Beneath each box, the test that checks it, with the tutorial step or exercise that runs it: the entries are profiled, overtime above half an hour is approved, and no day shows everyone clocking the same hours; the labor hours equal the clock entry's and no direct time is recorded after its operation ended; the register pays its own employee's approved time at the employee's rate and is not approved by that employee; each approved register has a payment, made after approval; and every payment posting traces to a payment, with unpaid wages accrued at the year-end.
Figure 12.7 · The Chain of Records Behind the Labor Cost

Isolated exceptions and systematic patterns

  • An isolated exception usually shows a control that did not operate
  • A systematic pattern more often shows a control missing or poorly designed
  • Both are control deficiencies; which kind depends on the cause
  • A pattern can mean the records cannot support some conclusions

A recalculation tests arithmetic, not hours

  • A substantive analytical procedure compares an amount with an expectation
  • The expectation comes from a plausible relationship; the threshold is set in advance
  • For payroll, each line’s hours times the employee’s rate recompute the pay
  • That is a recalculation: it tests the arithmetic, not whether the hours were worked

Check your understanding

Isolated exception or systematic pattern?

  1. A register paid to an employee who had left
  2. Most direct time recorded after its operation ended
  3. One unapproved overtime entry
  4. Every hourly employee clocking the same minutes on many days

Each exception has its kind

  1. Isolated: a control that did not operate
  2. A pattern: a control missing or poorly designed
  3. Isolated: one entry that needs a disposition
  4. A pattern: time that looks entered in bulk

Guided Tutorial 12.3: Testing the Hours Behind the Variance

Steps 1 to 5: profile, reconcile and test the pay

  1. Profile the time records
  2. Reconcile the hours along the chain
  3. Look at the months with little indirect time
  4. Test whose time was paid
  5. Recalculate the pay from the hours and the rates

Steps 6 to 10: overtime, surge days and late time

  1. Test overtime against its approvals
  2. Look for days on which everyone clocked the same hours
  3. Test the work dates of direct labor
  4. Find where the late time was charged
  5. Complete and save the script

Surge days carried more and more of the overtime

Detail of the result grid of the surge day test, one row for each of 2024, 2025 and 2026, with the columns WorkYear, SurgeDays, EmployeesPerDay, SurgeOvertime and SurgeShare. The outlined SurgeDays column rises each year, EmployeesPerDay is the same 64 in every row, and the outlined SurgeShare column rises from about a third to more than two-thirds.
Figure 12.8 · Days on Which Every Hourly Manufacturing Employee Clocked the Same Hours (detail)

On an ordinary day, times and hours differ

Detail of the time clock entries of six Assemblers on a day in March 2024, before the first surge day, with the columns Employee, Clock in, Clock out, Regular, Overtime and Overtime approved by. The clock times and the regular hours differ from one employee to the next, and only some of the six recorded overtime, approved by the Production Manager on the work date. A line below summarizes the day for all 64 hourly employees, with many different clock-in times and numbers of hours.
Figure 12.9 · A Day Before the Surge Days and a Surge Day (detail)

On a surge day, everyone clocks the same minutes

Detail of the time clock entries of the same six Assemblers on a surge day in June 2026. The outlined clock-in, clock-out, regular and overtime cells are identical from row to row, with one employee on the second shift, and all the overtime is approved by the Production Manager on the work date. A line below says that all 64 hourly employees clocked in at one of two times, recorded the same hours, and recorded overtime.
Figure 12.9 · A Day Before the Surge Days and a Surge Day (detail)

Late direct time grew, mostly on surge days

Detail of the result grid of the late direct time test, one row for each of 2024, 2025 and 2026, with the columns WorkYear, DirectHours, AfterEnd, ShareAfterEnd and AfterEndOnSurgeDays. The outlined ShareAfterEnd column rises from about a fifth to about half and then about two-thirds, and the outlined AfterEndOnSurgeDays column holds most of the AfterEnd hours in every year.
Figure 12.10 · Direct Labor Recorded After Its Operation Ended (detail)

Checkpoint

Check that:

  • the profile finds a handful of entries awaiting approval and three with no clock-out time, in records that end on December 11, 2026;
  • clocked, recorded, and paid hours agree in every pay period the records share, and the manufacturing hours of February to May 2024 are recorded like any others, most of them direct;
  • six earnings lines pay a terminated employee’s time to others, two of them to an Assembler, and eight rest on unapproved clock entries;
  • every earnings line agrees with the recalculation from its hours and the employee’s rate to within a cent;

Checkpoint (continued)

  • long overtime has an approval linked, except three entries of the terminated employee whose approvals are not linked;
  • on a growing number of days every hourly manufacturing employee clocked the same hours, and by fiscal 2026 those days carried more than two-thirds of the plant’s overtime;
  • the share of direct time recorded after its operation ended rose to about two-thirds, most of it on surge days and at Packing;
  • Audit.sql is saved with a completed header and a comment above each test.

12.10 Chapter 8’s Tests in SQL

Chapter 8’s tests become queries

  • An aging or a stratification is a CASE, counted and totaled with GROUP BY
  • Days past due come from julianday and an as-of date in a one-row CTE
  • Duplicate invoices or payments: GROUP BY with HAVING more than one row
  • Near-duplicates: a self-join on supplier and amount within a window of days

Sequences and first digits

  • LAG compares each document number with the one before it
  • A series that restarts each year is partitioned by year
  • printf('%.15e', Amount) writes the first significant digit first
  • LOG10(1 + 1.0 / Digit) gives Benford’s expectation for each digit

Watch out: a self-join pairs every row twice

  • Without b.DisbursementID > a.DisbursementID, a row pairs with itself
  • And every other pair is listed twice, once in each order
  • A condition on the dates removes only the first problem
  • Count the rows with and without the condition before you trust it

12.11 A Library of Audit Queries

The library’s ledger tests

Table 12.1 · The audit query library of this chapter

Tests What they test Technique Expected result
L1–L2 Journal entries and manufacturing payroll against the ledger Aggregates, scalar subqueries Agree to the cent
L3–L4 Postings traced to payments, and invoices to postings; unpaid registers Anti-joins, UNION ALL No rows
L5–L6 Revenue outside the year of delivery; shipments never invoiced CTEs, CASE, anti-join No rows
L7–L8 Pay periods across a year-end; accrued payroll Derived table, aggregates Unpaid wages accrued

The library’s purchasing and hours tests

Table 12.1 · The audit query library of this chapter

Tests What they test Technique Expected result
P1–P3 Three-way match, price tolerance, receipts not invoiced CTEs, CASE, tolerances No exceptions; within rounding of account 2020
P4–P6 Purchase order approvals and their concentration UNION ALL, joins to Employee No rows; approval shared
H1–H3 Time records profiled; hours clocked, recorded, and paid; the hours of 2024 Aggregates, CTEs, CASE Complete; equal
H4–H5 Whose time was paid; pay recalculated from hours and rates Joins, UNION ALL, CTE No rows; within a cent
H6–H8 Overtime approvals; days on which everyone clocked the same hours CASE, left joins, CTE Approved; no such days
H9–H10 Direct time dated after its operation ended Inner join to operations, left join to a CTE A small share

Each test opens with what it tests

Detail of the editor holding Audit.sql, without the note under it. A header comment names the purpose of the script, the database, the preparer and reviewer, and the checks. Below it, the first test begins with a two-line comment that gives its tutorial and test number, its objective, its population and its expected result, followed by the query that reconciles the journal entries to the ledger with four scalar subqueries.
Figure 12.11 · The Start of an Audit Query Library (detail)

The library needs the controls it tests

  • Save each test as a view; count the rows of those that list exceptions
  • Review and record every change to a test
  • Keep each run’s results as a workpaper: the date, the data, the reviewer and each item’s key
  • A library that anyone can change without a record undermines its evidence

12.12 Looking Ahead

What the audit found

  • The ledger reconciles and traces, but no year-end accrues the late wages
  • Purchasing matches, with approval exceptions and one dominant approver
  • The hours were clocked, recorded and paid; the quiet months match a stock build
  • The surge-day overtime cannot be corroborated from the records alone

Do the standards still fit?

  • These tests give no reason to revise them, though they do not show they are right
  • What grew is the time paid beyond the work: indirect time and overtime
  • In the records, the hours grew around the work, not in it
  • Part of the growth is the calendar: the first year charged two payrolls fewer

Summary

  • Reconcile and profile a population before testing it
  • Anti-joins trace both ways, UNION ALL lists the exceptions, dates test cutoff
  • The three-way match compares sums at the order line, within tolerances
  • Approval tests check each approver’s authority and concentration
  • The chain behind a cost is tested link by link, with the pay recalculated

Key terms

Audit query library · Concentration of approval · Cutoff · Existence and completeness tests · Full-population testing · Goods received not invoiced · Price tolerance · Self-join · Substantive analytical procedure · Three-way match · UNION ALL · Unrecorded liability

Practice and next steps

  • Financial Accounting
    • Exercise 12.1: Cutoff at Each Year-End
    • Exercise 12.2: Aging the Open Balances
  • Managerial Accounting
    • Exercise 12.3: Where Did the Time Go?
    • Exercise 12.4: Is the Overtime Approval Doing Its Job?
  • Auditing
    • Exercise 12.5: Who Was Paid, and Who Approved the Pay?
    • Exercise 12.6: Chapter 8’s Tests in SQL

Next: Comprehensive Case: Planning the Plant’s Hours for 2027

About these slides

These slides accompany Accounting Analytics: An Integrated Approach, licensed under CC BY-SA 4.0. Every figure and table comes from the chapter:

https://aa.accountinganalyticshub.com/chapters/12-sql-audit-analytics/chapter.html