Files
InboundVerify/schema.sql
Misaka 44c84983b4 refactor(ingest): unique key (site,handover_no,waybill_no) + business_date purge + shortfall-sum undelivered
- schema: expected_record unique key (site,waybill_no) -> (site,handover_no,waybill_no),
  so the same waybill can belong to multiple handover batches without being overwritten
- store: dedup by (handover_no,waybill_no) instead of waybill_no alone; UPSERT conflict
  key matches the new unique key; handover_no no longer force-overwritten on conflict
- store: add purge_expected, called on force re-download; deletes by business_date
  (download day, same source as task date) rather than batch_out_date, which is offset
  from the download day for sites like yunda where download day != outbound day
- store/runtime: thread force + target_date through ingest_task / _persist_to_db /
  _site_undelivered_handler so force re-download purges then re-ingests in one tx
- db_compare: undelivered_pieces now sums per-waybill shortfall (total - arrived)
  instead of expected_total - arrived_total, unaffected by unrelated/extra scans
2026-08-09 20:37:29 +08:00

87 lines
4.8 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =====================================================================
-- CQHXDB / 到货核销数据持久化 schema
-- 设计:统一核心表 + JSONB raw 兜底(保留站点原始全列,一字段不丢)
-- 幂等:业务唯一键 UPSERT重复下载天然合并、零冗余
-- 表expected_record运单级/ actual_record扫描件级
-- / undelivered_record百世站点直供未到明细子单级
-- =====================================================================
-- 隔离到专用 schema不污染 public表名无需再加前缀。
CREATE SCHEMA IF NOT EXISTS inbound_verify;
SET search_path TO inbound_verify;
-- 应到货物(运单级:一运单一批次一行;同运单可跨批次,按 交接单号+运单号 去重后入库)
CREATE TABLE IF NOT EXISTS expected_record (
id BIGSERIAL PRIMARY KEY,
site TEXT NOT NULL, -- 站点:顺心 / 中通 / 韵达 / 安能
waybill_no TEXT NOT NULL, -- 运单基号
handover_no TEXT, -- 交接单号
handover_pieces INTEGER, -- 交接件数(应到件数口径)
order_pieces INTEGER, -- 录单件数
business_date DATE, -- 业务日期(属性,非唯一键;读不到则 NULL
out_date DATE, -- 出库日(批次归属日口径;从 raw.出库时间 解析)
batch_out_date DATE, -- 批次归属日(同交接单号出库日众数,并列取较早)
raw JSONB NOT NULL, -- 站点原始全列key=原列名)
ingested_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (site, handover_no, waybill_no)
);
-- 迁移:旧唯一键 (site, waybill_no) → 新 (site, handover_no, waybill_no)。
-- CREATE TABLE IF NOT EXISTS 不改已存在的表,故用幂等 ALTER 切换约束。
ALTER TABLE expected_record DROP CONSTRAINT IF EXISTS expected_record_site_waybill_no_key;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint
WHERE conname = 'expected_record_site_handover_waybill_key'
) THEN
ALTER TABLE expected_record
ADD CONSTRAINT expected_record_site_handover_waybill_key
UNIQUE (site, handover_no, waybill_no);
END IF;
END $$;
CREATE INDEX IF NOT EXISTS idx_expected_site_date ON expected_record (site, business_date);
CREATE INDEX IF NOT EXISTS idx_expected_handover ON expected_record (site, handover_no);
CREATE INDEX IF NOT EXISTS idx_expected_out_date ON expected_record (site, out_date);
CREATE INDEX IF NOT EXISTS idx_expected_batch_out_date ON expected_record (site, batch_out_date);
-- 实到货物(扫描件级:一扫描一行;每扫描一件系统生成一个单号)
CREATE TABLE IF NOT EXISTS actual_record (
id BIGSERIAL PRIMARY KEY,
site TEXT NOT NULL,
waybill_no TEXT NOT NULL, -- 运单基号(由扫描单号推导)
piece_no TEXT NOT NULL, -- 扫描单号 / 子单号(业务唯一键)
scan_time TIMESTAMPTZ, -- 扫描时间(尽力解析,失败存 NULL原始值在 raw
scan_site TEXT, -- 扫描网点
raw JSONB NOT NULL,
ingested_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (site, piece_no)
);
CREATE INDEX IF NOT EXISTS idx_actual_waybill ON actual_record (site, waybill_no);
CREATE INDEX IF NOT EXISTS idx_actual_scan_time ON actual_record (scan_time);
-- 应到未到(百世站点直供未到明细:子单级)
CREATE TABLE IF NOT EXISTS undelivered_record (
id BIGSERIAL PRIMARY KEY,
site TEXT NOT NULL, -- 百世
waybill_no TEXT, -- 运单号
piece_no TEXT, -- 子单号(业务唯一键)
biz_type TEXT, -- 类型
last_scan TEXT, -- 最新扫描记录
raw JSONB NOT NULL,
ingested_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (site, piece_no)
);
-- 百世日聚合(应扫/已扫基数:站级日聚合,区别于运单级/件级/子单级表)
CREATE TABLE IF NOT EXISTS baishi_daily_stats (
id BIGSERIAL PRIMARY KEY,
site TEXT NOT NULL, -- 百世
business_date DATE NOT NULL, -- 业务日期(百世固定当天)
expected_pieces INTEGER, -- 应扫(应到基数)
arrived_pieces INTEGER, -- 已扫(实到基数)
undelivered_pieces INTEGER, -- 未扫(=应扫-已扫,任一缺失则 NULL
raw JSONB NOT NULL, -- 原始抓取值
ingested_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (site, business_date)
);