订单显示“已付款”,交付记录显示“完成”,账户里却还需要确认 Plus 状态:这三个记录回答的是不同问题。自建订单系统如果把它们压成一个“成功”字段,客服和用户就容易各说各话。
下面用一组构造订单和人工套餐观察记录,演示一条 SQLite 对账查询。查询为每个订单给出确认付款、继续处理、补充证据或核对套餐等下一步,方便定位和跟进。
支付记录表示系统是否确认收款;交付记录表示订单系统是否完成自己的交付步骤;套餐证据表示某个账户在某个观察时间显示了什么套餐。交付一份操作指引或开通材料,不等于目标账户已经显示 Plus。
示例保留两个数据集合。orders 记录订单代号、目标账户代号、付款状态、交付状态和付款确认时间;evidence 记录关联订单、实际观察账户、套餐名称和观察时间。账户代号用于演示。实际系统应采用稳定的账户标识,确保观察记录对应订单的目标账户。
refunded 表示已有确认的退款记录。退款状态与会员状态分别保留,方便同时核对资金处理和订阅结果。
查询时点固定为北京时间 2026 年 9 月 8 日 12:00。所有时间先整理成同一种格式;本例只比较时间间隔,不做时区转换,也不混用 Unix 秒和本地时间文本。
“新鲜”暂定为查询前 30 分钟内,并且观察时间不早于付款确认时间。30 分钟是本例采用的证据新鲜度参数,实际取值由业务核验规则确定。超出窗口、晚于查询时点或账号不一致的记录,都转入复核。
同一订单有多条证据时,按观察时间选择最新一条,不按写入编号判断新旧。O04 特意放入一条编号较大、实际更早的 Free 记录,验证旧观察不会盖住较新的 Plus 观察。最新记录若存在账号或时间问题,本例保留问题等待复核,不回退到旧的有利记录。
保存下列内容为 reconciliation.sql,使用支持窗口函数的 SQLite 运行:sqlite3 :memory: < reconciliation.sql。数据由 CTE 中的 VALUES 提供,在内存中完成查询,可直接离线复现。
-- Constructed data; all timestamps use the same Beijing wall-clock format.
WITH
params(as_of) AS (VALUES ('2026-09-08 12:00:00')),
orders(order_key, target_account, payment_state, delivery_state, paid_at) AS (
VALUES
('O01', 'A01', 'pending', 'none', NULL),
('O02', 'A02', 'paid', 'processing', '2026-09-08 11:20:00'),
('O03', 'A03', 'paid', 'completed', '2026-09-08 11:20:00'),
('O04', 'A04', 'paid', 'completed', '2026-09-08 11:20:00'),
('O05', 'A05', 'paid', 'completed', '2026-09-08 11:20:00'),
('O06', 'A06', 'paid', 'completed', '2026-09-08 11:20:00'),
('O07', 'A07', 'refunded', 'completed', '2026-09-08 11:20:00'),
('O08', 'A08', 'paid', 'completed', '2026-09-08 11:20:00'),
('O09', 'A09', 'paid', 'completed', '2026-09-08 11:20:00')
),
evidence(evidence_id, order_key, account_key, plan_name, observed_at) AS (
VALUES
(1, 'O04', 'A04', 'plus', '2026-09-08 11:50:00'),
(2, 'O04', 'A04', 'free', '2026-09-08 11:10:00'),
(3, 'O05', 'A05', 'plus', '2026-09-08 11:25:00'),
(4, 'O06', 'B06', 'plus', '2026-09-08 11:55:00'),
(5, 'O07', 'A07', 'plus', '2026-09-08 11:55:00'),
(6, 'O08', 'A08', 'free', '2026-09-08 11:55:00'),
(7, 'O09', 'A09', 'plus', '2026-09-08 12:05:00')
),
ranked AS (
SELECT e.*, ROW_NUMBER() OVER (
PARTITION BY order_key
ORDER BY julianday(observed_at) DESC, evidence_id DESC
) AS rn
FROM evidence AS e
),
checked AS (
SELECT o.*, p.as_of,
CASE
WHEN e.evidence_id IS NULL THEN 'no_record'
WHEN o.target_account IS NULL OR trim(o.target_account) = ''
OR e.account_key IS NULL OR trim(e.account_key) = ''
OR e.account_key <> o.target_account
THEN 'account_mismatch'
WHEN julianday(e.observed_at) IS NULL
OR julianday(e.observed_at) > julianday(p.as_of)
THEN 'invalid_time'
WHEN julianday(o.paid_at) IS NULL THEN 'payment_time_unknown'
WHEN julianday(e.observed_at) < julianday(o.paid_at)
OR julianday(e.observed_at) < julianday(p.as_of, '-30 minutes')
THEN 'stale'
WHEN e.plan_name = 'plus' THEN 'recent_plus'
WHEN e.plan_name IS NULL OR trim(e.plan_name) = '' THEN 'unknown_plan'
ELSE 'recent_other_plan'
END AS evidence_state
FROM orders AS o CROSS JOIN params AS p
LEFT JOIN ranked AS e ON e.order_key = o.order_key AND e.rn = 1
)
SELECT order_key, payment_state, delivery_state, evidence_state,
CASE
WHEN payment_state = 'refunded' THEN 'refund_review'
WHEN payment_state IS NULL OR payment_state <> 'paid' THEN 'confirm_payment'
WHEN julianday(paid_at) IS NULL OR julianday(paid_at) > julianday(as_of)
THEN 'check_payment_time'
WHEN evidence_state = 'recent_plus' THEN 'plus_observed'
WHEN evidence_state <> 'no_record' THEN 'review_evidence'
WHEN delivery_state = 'processing' THEN 'processing'
ELSE 'verify_plan'
END AS next_step
FROM checked
ORDER BY order_key;查询保留原始付款和交付状态,另给出 evidence_state 与 next_step。九个样例的下一步如下:
订单 | 下一步输出 | 对应含义 |
|---|---|---|
O01 | confirm_payment | 支付尚未确认 |
O02 | processing | 已付,交付记录仍在处理 |
O03 | verify_plan | 交付记录完成,套餐尚无证据 |
O04 | plus_observed | 有同账号、新鲜且晚于付款的 Plus 观察 |
O05 | review_evidence | 观察已超出新鲜度窗口 |
O06 | review_evidence | 观察账户与目标账户不同 |
O07 | refund_review | 退款记录需与订阅状态分别核对 |
O08 | review_evidence | 同账号近期显示 Free,继续复核 |
O09 | review_evidence | 观察时间在未来,不采用该证据 |
O03 接下来补充套餐观察,O08 则核对当前套餐与预期结果的差异。把同账号、带观察时间的记录补齐后,再运行查询更新处理方向。
O04 记录的是“该账号观察时显示 Plus”。续费场景还需对比有效期与本次订单对应的订阅周期,以确认新增时长。
实际接入时,把 orders 替换成可靠的订单与付款记录,把 evidence 替换成已关联目标账号的套餐观察。交付完成对应的具体步骤应有统一定义;部分退款、重复事件与同一时刻存在冲突的观察,另设处理分支。
本次离线核验的九个核心情形和十一个边界用例全部通过,覆盖缺少目标账号、付款时间缺失、证据早于付款、窗口边界及更新观察等情况。
保留原始的支付、交付和套餐记录,将查出的差异交给相应处理流程。每次补齐新证据后重新核验,处理人员就能看到问题推进到了哪一步。
语法依据:SQLite 官方的 WITH 子句、窗口函数与日期时间函数。CTE 用于组织样本,窗口函数选择观察记录,日期函数用于比较统一格式的时间。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。