runtime
56 / 88

lesson 56 Advanced product analysis · advanced

Revenue & payment reconciliation

Reconcile revenue with payments and identify differences.

the idea

Reconciliation compares two records of the same money. Bring each side to the same grain (one row per settlement), join them, and classify every row: matched, missing on one side, or different amounts. Unmatched rows are findings, not errors to filter away.

Dataset: Finance / Payments

The tables the challenges use, with their first 6 rows. Under each column name: the kind of value it holds, and which table it links to.

settlements4 columns · 37,071 rows
settlement_idnumber · unique idauthorization_idnumber · links to authorizationssettled_atdate & timeamount_centsnumber
132025-01-23 01:12:537655
242025-01-30 13:04:516852
352025-01-30 17:41:215771
462025-02-11 06:57:343717
572025-02-11 19:25:534401
682025-02-20 03:08:189288
settlement_idnumber · unique id
1
authorization_idnumber · links to authorizations
3
settled_atdate & time
2025-01-23 01:12:53
amount_centsnumber
7655
settlement_idnumber · unique id
2
authorization_idnumber · links to authorizations
4
settled_atdate & time
2025-01-30 13:04:51
amount_centsnumber
6852
settlement_idnumber · unique id
3
authorization_idnumber · links to authorizations
5
settled_atdate & time
2025-01-30 17:41:21
amount_centsnumber
5771
settlement_idnumber · unique id
4
authorization_idnumber · links to authorizations
6
settled_atdate & time
2025-02-11 06:57:34
amount_centsnumber
3717
settlement_idnumber · unique id
5
authorization_idnumber · links to authorizations
7
settled_atdate & time
2025-02-11 19:25:53
amount_centsnumber
4401
settlement_idnumber · unique id
6
authorization_idnumber · links to authorizations
8
settled_atdate & time
2025-02-20 03:08:18
amount_centsnumber
9288

first 6 of 37,071 rows · your queries use all of them

refunds5 columns · 1,230 rows
refund_idnumber · unique idsettlement_idnumber · links to settlementsrefunded_atdate & timeamount_centsnumberreasontext
1252025-02-12 02:56:322820returned_item
2272025-03-01 03:02:5211883returned_item
32682025-03-01 07:28:00367canceled_service
43132025-05-30 14:18:371601returned_item
53132025-06-15 14:18:372440canceled_service
63482025-05-11 19:21:1719843price_adjustment
refund_idnumber · unique id
1
settlement_idnumber · links to settlements
25
refunded_atdate & time
2025-02-12 02:56:32
amount_centsnumber
2820
reasontext
returned_item
refund_idnumber · unique id
2
settlement_idnumber · links to settlements
27
refunded_atdate & time
2025-03-01 03:02:52
amount_centsnumber
11883
reasontext
returned_item
refund_idnumber · unique id
3
settlement_idnumber · links to settlements
268
refunded_atdate & time
2025-03-01 07:28:00
amount_centsnumber
367
reasontext
canceled_service
refund_idnumber · unique id
4
settlement_idnumber · links to settlements
313
refunded_atdate & time
2025-05-30 14:18:37
amount_centsnumber
1601
reasontext
returned_item
refund_idnumber · unique id
5
settlement_idnumber · links to settlements
313
refunded_atdate & time
2025-06-15 14:18:37
amount_centsnumber
2440
reasontext
canceled_service
refund_idnumber · unique id
6
settlement_idnumber · links to settlements
348
refunded_atdate & time
2025-05-11 19:21:17
amount_centsnumber
19843
reasontext
price_adjustment

first 6 of 1,230 rows · your queries use all of them

transactions12 columns · 84,798 rows
transaction_idnumber · unique idaccount_idnumber · links to accountstransaction_typetextstatustextamount_centsnumberinitiated_atdate & timeposted_atdate & timedescriptiontextmerchant_idnumber · links to merchantsauthorization_idnumber · links to authorizationsrefund_idnumber · links to refundschargeback_idnumber · links to chargebacks
1103card_purchaseposted-13992025-01-01 04:00:002025-01-02 06:23:00TRUE STREAMING #7119591980NULLNULL
2377card_purchaseposted-39992025-01-01 04:00:002025-01-03 10:26:00VISTA GYM #1969656710NULLNULL
3442card_purchaseposted-6992025-01-01 04:00:002025-01-03 04:21:00WILLOW STREAMING #8179557848NULLNULL
4447card_purchaseposted-49992025-01-01 04:00:002025-01-02 12:31:00OAK GYM #9649697931NULLNULL
5450card_purchaseposted-24992025-01-01 04:00:002025-01-02 08:01:00BIRCH GYM #4989688096NULLNULL
6497card_purchaseposted-8992025-01-01 04:00:002025-01-02 12:11:00VERDE STREAMING #3859588870NULLNULL
transaction_idnumber · unique id
1
account_idnumber · links to accounts
103
transaction_typetext
card_purchase
statustext
posted
amount_centsnumber
-1399
initiated_atdate & time
2025-01-01 04:00:00
posted_atdate & time
2025-01-02 06:23:00
descriptiontext
TRUE STREAMING #711
merchant_idnumber · links to merchants
959
authorization_idnumber · links to authorizations
1980
refund_idnumber · links to refunds
NULL
chargeback_idnumber · links to chargebacks
NULL
transaction_idnumber · unique id
2
account_idnumber · links to accounts
377
transaction_typetext
card_purchase
statustext
posted
amount_centsnumber
-3999
initiated_atdate & time
2025-01-01 04:00:00
posted_atdate & time
2025-01-03 10:26:00
descriptiontext
VISTA GYM #196
merchant_idnumber · links to merchants
965
authorization_idnumber · links to authorizations
6710
refund_idnumber · links to refunds
NULL
chargeback_idnumber · links to chargebacks
NULL
transaction_idnumber · unique id
3
account_idnumber · links to accounts
442
transaction_typetext
card_purchase
statustext
posted
amount_centsnumber
-699
initiated_atdate & time
2025-01-01 04:00:00
posted_atdate & time
2025-01-03 04:21:00
descriptiontext
WILLOW STREAMING #817
merchant_idnumber · links to merchants
955
authorization_idnumber · links to authorizations
7848
refund_idnumber · links to refunds
NULL
chargeback_idnumber · links to chargebacks
NULL
transaction_idnumber · unique id
4
account_idnumber · links to accounts
447
transaction_typetext
card_purchase
statustext
posted
amount_centsnumber
-4999
initiated_atdate & time
2025-01-01 04:00:00
posted_atdate & time
2025-01-02 12:31:00
descriptiontext
OAK GYM #964
merchant_idnumber · links to merchants
969
authorization_idnumber · links to authorizations
7931
refund_idnumber · links to refunds
NULL
chargeback_idnumber · links to chargebacks
NULL
transaction_idnumber · unique id
5
account_idnumber · links to accounts
450
transaction_typetext
card_purchase
statustext
posted
amount_centsnumber
-2499
initiated_atdate & time
2025-01-01 04:00:00
posted_atdate & time
2025-01-02 08:01:00
descriptiontext
BIRCH GYM #498
merchant_idnumber · links to merchants
968
authorization_idnumber · links to authorizations
8096
refund_idnumber · links to refunds
NULL
chargeback_idnumber · links to chargebacks
NULL
transaction_idnumber · unique id
6
account_idnumber · links to accounts
497
transaction_typetext
card_purchase
statustext
posted
amount_centsnumber
-899
initiated_atdate & time
2025-01-01 04:00:00
posted_atdate & time
2025-01-02 12:11:00
descriptiontext
VERDE STREAMING #385
merchant_idnumber · links to merchants
958
authorization_idnumber · links to authorizations
8870
refund_idnumber · links to refunds
NULL
chargeback_idnumber · links to chargebacks
NULL

first 6 of 84,798 rows · your queries use all of them

worked example

Run these steps in order to see the idea before you write your own query. The step marked “the pattern” is what the challenges ask for. Running the example does not count toward progress.

  1. Summarize March ledger activity. Run this. Posted card purchases and other types in March 2025—the bank side of reconciliation.the pattern

    example.sql
    SELECT
      transaction_type,
      status,
      COUNT(*) AS entries,
      SUM(amount_cents) AS cents
    FROM transactions
    WHERE posted_at >= '2025-03-01' AND posted_at < '2025-04-01'
    GROUP BY transaction_type, status;
  2. Line up settlement and posting. Run this. Each settlement ties to card_purchase rows through authorization_id so you can compare amounts row by row.

    step-2.sql
    SELECT
      s.settlement_id,
      s.amount_cents,
      t.transaction_id,
      t.amount_cents AS ledger_cents
    FROM settlements s
    LEFT JOIN transactions t
      ON t.authorization_id = s.authorization_id
      AND t.transaction_type = 'card_purchase'
    WHERE s.settlement_id <= 5;
  3. Add partial refunds per charge. Run this. Several refund rows can share one settlement_id—sum them before you net against settled cents.

    step-3.sql
    SELECT
      settlement_id,
      COUNT(*) AS refunds,
      SUM(amount_cents) AS refunded_cents
    FROM refunds
    WHERE settlement_id <= 300
    GROUP BY settlement_id;
  4. Compare month totals. Run this. settled_cents from the card processor should line up with negated posted card_purchase cents when nothing is missing.

    step-4.sql
    SELECT
      (
        SELECT SUM(amount_cents)
        FROM settlements
        WHERE settled_at >= '2025-02-01' AND settled_at < '2025-03-01'
      ) AS settled_cents,
      (
        SELECT -SUM(amount_cents)
        FROM transactions
        WHERE transaction_type = 'card_purchase'
          AND status = 'posted'
          AND posted_at >= '2025-02-01'
          AND posted_at < '2025-03-01'
      ) AS ledger_cents;

common mistake

An inner join between settlements and ledger postings silently drops the settlements that never posted, which are exactly the problems to find.

challenge 1

For settlements settled in March 2025, return settlement_id, settled_cents, refunded_cents (0 when none) and net_cents (settled minus refunded).

what to return

Columns
settlement_idsettled_centsrefunded_centsnet_cents in this order
Rows
any order
challenge-1.sql
 
To master this lesson, solve both challenges without hints and pass the concept check. 3 of 3 to go.
Revenue & payment reconciliation — Advanced product analysis · Runtime