上传源代码版本

This commit is contained in:
Im-Jenisson
2026-06-01 16:30:29 +08:00
commit b2a9b7d3c2
462 changed files with 104365 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
-- 为 label_scan_history 表添加设备信息字段
-- 用于跟踪每条扫描记录是哪个设备产生的
-- 执行时间2026-05-28
ALTER TABLE `label_scan_history`
ADD COLUMN `DeviceCode` VARCHAR(64) NULL COMMENT '设备唯一编码GUID' AFTER `CreatedBy`,
ADD COLUMN `DeviceName` VARCHAR(100) NULL COMMENT '设备名称(计算机名)' AFTER `DeviceCode`;
-- 为设备编码添加索引,方便按设备查询/统计
ALTER TABLE `label_scan_history`
ADD INDEX `IX_DeviceCode` (`DeviceCode`);

View File

@@ -0,0 +1,145 @@
-- ==============================================================
-- 日汇总指标视图 - v_DailyMetricsSummary
-- 用途:一次查询获取所有日汇总指标,替代 11 个独立的 SQL 查询
-- 创建日期2026-05-17
-- 实际表名label_replace_requests, label_scan_history, arrival_handover_forms
-- ==============================================================
DROP VIEW IF EXISTS v_DailyMetricsSummary;
CREATE VIEW v_DailyMetricsSummary AS
SELECT
-- 日期信息
CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) AS MetricsDate,
-- 核心数量指标 - 当天新增换单数(有标签的订单)
COUNT(DISTINCT CASE
WHEN CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
AND r.Label IS NOT NULL
THEN r.Id
END) AS DailyNewReplaceCount,
-- 应该换单数 (新增 + 积压未完成)
COUNT(DISTINCT CASE
WHEN CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) <= CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
AND r.Label IS NOT NULL
THEN r.Id
END) AS DailyShouldReplaceCount,
-- 完成数 (成功扫描 Result=0)
COUNT(DISTINCT CASE
WHEN r.Label IS NOT NULL
AND s.Id IS NOT NULL
AND s.Result = 0
AND CAST(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
THEN r.Id
END) AS DailySuccessCount,
-- 累计未完成数 (历史数据中未完成的)
COUNT(DISTINCT CASE
WHEN r.Label IS NOT NULL
AND (s.Id IS NULL OR s.Result != 0)
AND CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) < CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
THEN r.Id
END) AS CumulativeTotalReplaceCount,
-- STOP 数 (ReplaceStatus = 'N')
COUNT(DISTINCT CASE
WHEN r.ReplaceStatus = 'N'
AND CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
THEN r.Id
END) AS DailyStopCount,
-- 标签推送数 (Label 不为空的订单)
COUNT(DISTINCT CASE
WHEN r.Label IS NOT NULL
AND CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
THEN r.Id
END) AS DailyLabelPushCount,
-- 扫描数 (当日扫描记录)
COUNT(DISTINCT CASE
WHEN CAST(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
THEN s.Id
END) AS DailyScanCount,
-- 16点前到仓数 (UTC-5 时区)
COUNT(DISTINCT CASE
WHEN HOUR(CONVERT_TZ(ahf.ReceiptTime, '+00:00', '-05:00')) < 16
AND CAST(CONVERT_TZ(ahf.ReceiptTime, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
THEN ahf.Id
END) AS BeforeNoonArrivedCount,
-- 16点后到仓数
COUNT(DISTINCT CASE
WHEN HOUR(CONVERT_TZ(ahf.ReceiptTime, '+00:00', '-05:00')) >= 16
AND CAST(CONVERT_TZ(ahf.ReceiptTime, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
THEN ahf.Id
END) AS AfternoonArrivedCount,
-- 16点前完成数
COUNT(DISTINCT CASE
WHEN HOUR(CONVERT_TZ(ahf.ReceiptTime, '+00:00', '-05:00')) < 16
AND CAST(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
AND s.Result = 0
THEN s.Id
END) AS BeforeNoonPassedCount,
-- 16点后完成数
COUNT(DISTINCT CASE
WHEN HOUR(CONVERT_TZ(ahf.ReceiptTime, '+00:00', '-05:00')) >= 16
AND CAST(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
AND s.Result = 0
THEN s.Id
END) AS AfternoonPassedCount,
-- 失败数 (应该完成但未完成)
COUNT(DISTINCT CASE
WHEN r.Label IS NOT NULL
AND (s.Id IS NULL OR s.Result != 0)
AND CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
THEN r.Id
END) AS DailyFailureCount,
-- 时间戳
NOW() AS DataFetchTime
FROM label_replace_requests r
LEFT JOIN label_scan_history s ON r.NeutralWaybillNumber = s.NeutralWaybillNumber
AND s.Id = (
SELECT Id FROM label_scan_history
WHERE NeutralWaybillNumber = r.NeutralWaybillNumber
ORDER BY CreatedAt ASC LIMIT 1
)
LEFT JOIN arrival_handover_forms ahf ON r.BillOfLadingNumber = ahf.HandoverNumber
OR r.MasterPackageNumber = ahf.HandoverNumber
WHERE r.Label IS NOT NULL
AND CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) >= DATE_SUB(CURDATE(), INTERVAL 90 DAY)
GROUP BY CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE);
-- ==============================================================
-- 索引优化(所有表已有足够的索引,无需添加)
-- ==============================================================
-- label_replace_requests 表现有索引:
-- idx_neutral_waybill_number (唯一)idx_created_atidx_replace_status
-- idx_customer_ididx_final_mile_tracking_number
-- idx_customer_id_created_at (复合)
-- label_scan_history 表现有索引:
-- IX_CustomerIdIX_NeutralWaybillNumberIX_ReferenceNumber
-- IX_FinalMileTrackingNumberIX_CreatedAtIX_Result
-- idx_customer_id_neutral_waybill_number (复合)
-- arrival_handover_forms 表现有索引:
-- UQ_HandoverNumber (唯一)
-- 结论:现有索引已足以支持视图查询,无需添加新索引
-- ==============================================================
-- 使用示例
-- ==============================================================
-- SELECT * FROM v_DailyMetricsSummary WHERE MetricsDate = '2026-05-17';

View File

@@ -0,0 +1,151 @@
DROP PROCEDURE IF EXISTS sp_GetDailyMetricsSummary;
DELIMITER $$
CREATE PROCEDURE sp_GetDailyMetricsSummary(IN p_date DATE)
BEGIN
DECLARE v_date_start DATETIME;
DECLARE v_date_end DATETIME;
DECLARE v_daily_new_replace_count INT;
DECLARE v_daily_should_replace_count INT;
DECLARE v_daily_success_count INT;
DECLARE v_daily_failure_count INT;
DECLARE v_cumulative_total_replace_count INT;
DECLARE v_daily_stop_count INT;
DECLARE v_daily_label_push_count INT;
DECLARE v_daily_scan_count INT;
DECLARE v_before_noon_arrived_count INT;
DECLARE v_afternoon_arrived_count INT;
DECLARE v_before_noon_passed_count INT;
DECLARE v_afternoon_passed_count INT;
SET v_date_start = CONVERT_TZ(CONCAT(DATE(p_date), ' 00:00:00'), '-05:00', '+00:00');
SET v_date_end = CONVERT_TZ(CONCAT(DATE(p_date), ' 23:59:59'), '-05:00', '+00:00');
SET v_daily_should_replace_count = (
SELECT COUNT(DISTINCT r.Id)
FROM label_replace_requests r
INNER JOIN arrival_handover_forms ahf
ON r.BillOfLadingNumber = ahf.HandoverNumber
OR r.MasterPackageNumber = ahf.HandoverNumber
WHERE r.Label IS NOT NULL
AND DATE(ahf.ReceiptTime) = p_date
);
SET v_daily_new_replace_count = v_daily_should_replace_count;
SET v_before_noon_arrived_count = (
SELECT COUNT(DISTINCT r.Id)
FROM label_replace_requests r
INNER JOIN arrival_handover_forms ahf
ON r.BillOfLadingNumber = ahf.HandoverNumber
OR r.MasterPackageNumber = ahf.HandoverNumber
WHERE r.Label IS NOT NULL
AND DATE(ahf.ReceiptTime) = p_date
AND HOUR(ahf.ReceiptTime) < 16
);
SET v_afternoon_arrived_count = (
SELECT COUNT(DISTINCT r.Id)
FROM label_replace_requests r
INNER JOIN arrival_handover_forms ahf
ON r.BillOfLadingNumber = ahf.HandoverNumber
OR r.MasterPackageNumber = ahf.HandoverNumber
WHERE r.Label IS NOT NULL
AND DATE(ahf.ReceiptTime) = p_date
AND HOUR(ahf.ReceiptTime) >= 16
);
SET v_daily_success_count = (
SELECT COUNT(DISTINCT s.NeutralWaybillNumber)
FROM label_scan_history s
WHERE s.Result = 0
AND s.CreatedAt >= v_date_start
AND s.CreatedAt <= v_date_end
);
SET v_before_noon_passed_count = (
SELECT COUNT(DISTINCT r.Id)
FROM label_replace_requests r
INNER JOIN arrival_handover_forms ahf
ON r.BillOfLadingNumber = ahf.HandoverNumber
OR r.MasterPackageNumber = ahf.HandoverNumber
INNER JOIN label_scan_history s ON r.NeutralWaybillNumber = s.NeutralWaybillNumber
WHERE r.Label IS NOT NULL
AND DATE(ahf.ReceiptTime) = p_date
AND HOUR(ahf.ReceiptTime) < 16
AND s.Result = 0
);
SET v_afternoon_passed_count = (
SELECT COUNT(DISTINCT r.Id)
FROM label_replace_requests r
INNER JOIN arrival_handover_forms ahf
ON r.BillOfLadingNumber = ahf.HandoverNumber
OR r.MasterPackageNumber = ahf.HandoverNumber
INNER JOIN label_scan_history s ON r.NeutralWaybillNumber = s.NeutralWaybillNumber
WHERE r.Label IS NOT NULL
AND DATE(ahf.ReceiptTime) = p_date
AND HOUR(ahf.ReceiptTime) >= 16
AND s.Result = 0
);
SET v_daily_stop_count = (
SELECT COUNT(DISTINCT s.NeutralWaybillNumber)
FROM label_scan_history s
WHERE s.CreatedAt >= v_date_start
AND s.CreatedAt <= v_date_end
AND s.Description IS NOT NULL
AND (LOWER(s.Description) LIKE '%stop%' OR s.Description LIKE '%停%' OR s.Description LIKE '%冻%')
);
SET v_daily_label_push_count = (
SELECT COUNT(DISTINCT r.Id)
FROM label_replace_requests r
WHERE r.Label IS NOT NULL
AND r.CreatedAt >= v_date_start
AND r.CreatedAt <= v_date_end
);
SET v_daily_scan_count = (
SELECT COUNT(DISTINCT s.Id)
FROM label_scan_history s
WHERE s.CreatedAt >= v_date_start
AND s.CreatedAt <= v_date_end
);
SET v_cumulative_total_replace_count = (
SELECT COUNT(DISTINCT r.Id)
FROM label_replace_requests r
LEFT JOIN label_scan_history s ON r.NeutralWaybillNumber = s.NeutralWaybillNumber AND s.Result = 0
INNER JOIN arrival_handover_forms ahf
ON r.BillOfLadingNumber = ahf.HandoverNumber
OR r.MasterPackageNumber = ahf.HandoverNumber
WHERE r.Label IS NOT NULL
AND ahf.ReceiptTime IS NOT NULL
AND DATE(ahf.ReceiptTime) < p_date
AND s.Id IS NULL
);
SET v_daily_failure_count = GREATEST(0, v_daily_should_replace_count - v_daily_success_count);
SELECT
p_date AS MetricsDate,
v_daily_new_replace_count AS DailyNewReplaceCount,
v_daily_should_replace_count AS DailyShouldReplaceCount,
v_daily_success_count AS DailySuccessCount,
v_cumulative_total_replace_count AS CumulativeTotalReplaceCount,
v_daily_stop_count AS DailyStopCount,
v_daily_label_push_count AS DailyLabelPushCount,
v_daily_scan_count AS DailyScanCount,
v_before_noon_arrived_count AS BeforeNoonArrivedCount,
v_afternoon_arrived_count AS AfternoonArrivedCount,
v_before_noon_passed_count AS BeforeNoonPassedCount,
v_afternoon_passed_count AS AfternoonPassedCount,
v_daily_failure_count AS DailyFailureCount,
NOW() AS DataFetchTime;
END$$
DELIMITER ;

View File

@@ -0,0 +1,3 @@
ALTER TABLE label_replace_requests
ADD INDEX IF NOT EXISTS idx_bill_of_lading_number (BillOfLadingNumber),
ADD INDEX IF NOT EXISTS idx_master_package_number (MasterPackageNumber);

View File

@@ -0,0 +1,472 @@
DROP PROCEDURE IF EXISTS sp_GetOperationsMonitor;
DELIMITER $$
CREATE PROCEDURE sp_GetOperationsMonitor()
BEGIN
DROP TEMPORARY TABLE IF EXISTS tmp_scan_agg;
DROP TEMPORARY TABLE IF EXISTS tmp_daily_scan;
DROP TEMPORARY TABLE IF EXISTS tmp_form_order;
DROP TEMPORARY TABLE IF EXISTS tmp_form_first_scan;
DROP TEMPORARY TABLE IF EXISTS tmp_form_stats;
DROP TEMPORARY TABLE IF EXISTS tmp_form_push_ranked;
DROP TEMPORARY TABLE IF EXISTS tmp_order_full;
DROP TEMPORARY TABLE IF EXISTS tmp_should_replace_dedup;
DROP TEMPORARY TABLE IF EXISTS tmp_label_push;
DROP TEMPORARY TABLE IF EXISTS tmp_daily_metrics;
-- ================================================================
-- 步骤1atmp_scan_agg - 每个运单的扫描摘要
-- 一次全量扫描 label_scan_history消除后续所有重复扫描
-- ================================================================
CREATE TEMPORARY TABLE tmp_scan_agg (
NeutralWaybillNumber VARCHAR(100) NOT NULL,
MinScanTime DATETIME NULL,
FirstSuccessTime_UTC5 DATETIME NULL,
FirstSuccessDate_UTC5 DATE NULL,
IsSuccess TINYINT NOT NULL DEFAULT 0,
IsStopLabel TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (NeutralWaybillNumber)
);
INSERT INTO tmp_scan_agg
SELECT
NeutralWaybillNumber,
MIN(CreatedAt),
MIN(CASE WHEN Result = 0 THEN CONVERT_TZ(CreatedAt, '+00:00', '-05:00') END),
DATE(MIN(CASE WHEN Result = 0 THEN CONVERT_TZ(CreatedAt, '+00:00', '-05:00') END)),
MAX(CASE WHEN Result = 0 THEN 1 ELSE 0 END),
MAX(CASE WHEN Result = 0 AND Description LIKE '%成功返回STOP标签%' THEN 1 ELSE 0 END)
FROM label_scan_history
GROUP BY NeutralWaybillNumber;
-- ================================================================
-- 步骤1btmp_daily_scan - 每日扫描统计(扫描数/完成数/失败数/STOP数
-- 与步骤1a共用同一次 label_scan_history 扫描
-- ================================================================
CREATE TEMPORARY TABLE tmp_daily_scan (
DATE NOT NULL,
INT NOT NULL DEFAULT 0,
INT NOT NULL DEFAULT 0,
INT NOT NULL DEFAULT 0,
STOP数 INT NOT NULL DEFAULT 0,
PRIMARY KEY ()
);
INSERT INTO tmp_daily_scan (, , , STOP数)
SELECT
DATE(CONVERT_TZ(CreatedAt, '+00:00', '-05:00')),
COUNT(*),
COUNT(DISTINCT CASE WHEN Result = 0 THEN NeutralWaybillNumber END),
COUNT(DISTINCT CASE WHEN Result = 0 AND Description LIKE '%成功返回STOP标签%' THEN NeutralWaybillNumber END)
FROM label_scan_history
GROUP BY DATE(CONVERT_TZ(CreatedAt, '+00:00', '-05:00'));
UPDATE tmp_daily_scan ds
INNER JOIN (
SELECT
DATE(CONVERT_TZ(h.CreatedAt, '+00:00', '-05:00')) AS ,
COUNT(DISTINCT h.NeutralWaybillNumber) AS
FROM label_scan_history h
INNER JOIN tmp_scan_agg sa ON h.NeutralWaybillNumber = sa.NeutralWaybillNumber
WHERE h.Result != 0
AND sa.IsSuccess = 0
GROUP BY DATE(CONVERT_TZ(h.CreatedAt, '+00:00', '-05:00'))
) fail_data ON ds. = fail_data.
SET ds. = fail_data.;
-- ================================================================
-- 步骤2tmp_form_order - 关联交接单和换单请求
-- 先对 arrival_handover_forms 两次索引查找HandoverNumber 有唯一索引)
-- 加上步骤1新建的 idx_master_package_number / idx_bill_of_lading_number 索引
-- ================================================================
CREATE TEMPORARY TABLE tmp_form_order (
FormId INT NOT NULL,
HandoverNumber VARCHAR(100) NOT NULL,
ReceiptTime DATETIME NULL,
ReceiptDate DATE NULL,
ReceiptHour TINYINT NULL,
RequestId INT NOT NULL,
NeutralWaybillNumber VARCHAR(100) NOT NULL,
LabelRetrievedAt_UTC5 DATETIME NULL,
LabelRetrievedDate_UTC5 DATE NULL,
RequestCreatedAt DATETIME NOT NULL,
HasLabel TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (RequestId),
INDEX idx_form_id (FormId),
INDEX idx_waybill (NeutralWaybillNumber),
INDEX idx_receipt_date (ReceiptDate),
INDEX idx_label_date (LabelRetrievedDate_UTC5)
);
INSERT INTO tmp_form_order
SELECT
COALESCE(f_m.Id, f_b.Id) AS FormId,
COALESCE(f_m.HandoverNumber, f_b.HandoverNumber) AS HandoverNumber,
COALESCE(f_m.ReceiptTime, f_b.ReceiptTime) AS ReceiptTime,
DATE(COALESCE(f_m.ReceiptTime, f_b.ReceiptTime)) AS ReceiptDate,
HOUR(COALESCE(f_m.ReceiptTime, f_b.ReceiptTime)) AS ReceiptHour,
r.Id AS RequestId,
r.NeutralWaybillNumber,
CASE WHEN r.LabelRetrievedAt IS NOT NULL
THEN CONVERT_TZ(r.LabelRetrievedAt, '+00:00', '-05:00') END AS LabelRetrievedAt_UTC5,
DATE(CONVERT_TZ(r.LabelRetrievedAt, '+00:00', '-05:00')) AS LabelRetrievedDate_UTC5,
r.CreatedAt AS RequestCreatedAt,
CASE WHEN r.Label IS NOT NULL AND r.Label != '' THEN 1 ELSE 0 END AS HasLabel
FROM label_replace_requests r
LEFT JOIN arrival_handover_forms f_m ON r.MasterPackageNumber = f_m.HandoverNumber
LEFT JOIN arrival_handover_forms f_b ON r.BillOfLadingNumber = f_b.HandoverNumber
WHERE COALESCE(f_m.Id, f_b.Id) IS NOT NULL;
-- ================================================================
-- 步骤3tmp_form_first_scan - 每个交接单的首次扫描时间
-- 直接读取 tmp_scan_agg无需再扫 label_scan_history
-- ================================================================
CREATE TEMPORARY TABLE tmp_form_first_scan (
FormId INT NOT NULL,
FirstScanTime_UTC5 DATETIME NULL,
PRIMARY KEY (FormId)
);
INSERT INTO tmp_form_first_scan
SELECT
fo.FormId,
CONVERT_TZ(MIN(sa.MinScanTime), '+00:00', '-05:00')
FROM tmp_form_order fo
LEFT JOIN tmp_scan_agg sa ON fo.NeutralWaybillNumber = sa.NeutralWaybillNumber
GROUP BY fo.FormId;
-- ================================================================
-- 步骤4tmp_form_stats - 每个交接单的总数、达标阈值和首次达标时间
-- ================================================================
CREATE TEMPORARY TABLE tmp_form_stats (
FormId INT NOT NULL,
TotalOrderCount INT NOT NULL DEFAULT 0,
QualifyNeedCount INT NOT NULL DEFAULT 0,
FirstQualifiedTime_UTC5 DATETIME NULL,
PRIMARY KEY (FormId)
);
INSERT INTO tmp_form_stats (FormId, TotalOrderCount, QualifyNeedCount)
SELECT
FormId,
COUNT(DISTINCT RequestId),
CEIL(COUNT(DISTINCT RequestId) * 0.8)
FROM tmp_form_order
GROUP BY FormId;
CREATE TEMPORARY TABLE tmp_form_push_ranked (
FormId INT NOT NULL,
LabelRetrievedAt_UTC5 DATETIME NULL,
PushOrder INT NOT NULL,
QualifyNeedCount INT NOT NULL,
INDEX idx_form_push (FormId, PushOrder)
);
INSERT INTO tmp_form_push_ranked
SELECT
fo.FormId,
fo.LabelRetrievedAt_UTC5,
ROW_NUMBER() OVER (PARTITION BY fo.FormId ORDER BY fo.LabelRetrievedAt_UTC5),
fs.QualifyNeedCount
FROM tmp_form_order fo
INNER JOIN tmp_form_stats fs ON fo.FormId = fs.FormId
WHERE fo.HasLabel = 1 AND fo.LabelRetrievedAt_UTC5 IS NOT NULL;
UPDATE tmp_form_stats fs
INNER JOIN (
SELECT
FormId,
MIN(LabelRetrievedAt_UTC5) AS FirstQualifiedTime_UTC5
FROM tmp_form_push_ranked
WHERE PushOrder >= QualifyNeedCount
GROUP BY FormId
) q ON fs.FormId = q.FormId
SET fs.FirstQualifiedTime_UTC5 = q.FirstQualifiedTime_UTC5;
DROP TEMPORARY TABLE IF EXISTS tmp_form_push_ranked;
-- ================================================================
-- 步骤5tmp_order_full - 每个有标签订单的完整信息(含考核时间)
-- 预先计算 AssessmentBaseTime / AssessmentTime / AssessmentDate
-- 避免后续重复展开 GREATEST() CASE WHEN
-- ================================================================
CREATE TEMPORARY TABLE tmp_order_full (
RequestId INT NOT NULL,
FormId INT NOT NULL,
NeutralWaybillNumber VARCHAR(100) NOT NULL,
HasLabel TINYINT NOT NULL DEFAULT 0,
ReceiptDate DATE NULL,
ReceiptTime DATETIME NULL,
LabelRetrievedDate_UTC5 DATE NULL,
LabelRetrievedAt_UTC5 DATETIME NULL,
RequestCreatedDate_UTC5 DATE NULL,
AssessmentBaseTime DATETIME NULL,
AssessmentBaseDate DATE NULL,
AssessmentTime DATETIME NULL,
AssessmentDate DATE NULL,
FirstSuccessTime_UTC5 DATETIME NULL,
FirstSuccessDate_UTC5 DATE NULL,
IsSuccess TINYINT NOT NULL DEFAULT 0,
IsStopLabel TINYINT NOT NULL DEFAULT 0,
IsCompletedInAssessment TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (RequestId),
INDEX idx_receipt_date (ReceiptDate),
INDEX idx_label_date (LabelRetrievedDate_UTC5),
INDEX idx_success_date (FirstSuccessDate_UTC5),
INDEX idx_assessment_base (AssessmentBaseDate),
INDEX idx_assessment_date (AssessmentDate),
INDEX idx_created_date (RequestCreatedDate_UTC5),
INDEX idx_success_label_date (IsSuccess, LabelRetrievedDate_UTC5, FirstSuccessDate_UTC5)
);
INSERT INTO tmp_order_full
SELECT
fo.RequestId,
fo.FormId,
fo.NeutralWaybillNumber,
fo.HasLabel,
fo.ReceiptDate,
fo.ReceiptTime,
fo.LabelRetrievedDate_UTC5,
fo.LabelRetrievedAt_UTC5,
DATE(CONVERT_TZ(fo.RequestCreatedAt, '+00:00', '-05:00')) AS RequestCreatedDate_UTC5,
GREATEST(
CASE
WHEN ffs.FirstScanTime_UTC5 IS NOT NULL
AND ffs.FirstScanTime_UTC5 < fo.ReceiptTime
THEN ffs.FirstScanTime_UTC5
ELSE fo.ReceiptTime
END,
fs.FirstQualifiedTime_UTC5
) AS AssessmentBaseTime,
DATE(GREATEST(
CASE
WHEN ffs.FirstScanTime_UTC5 IS NOT NULL
AND ffs.FirstScanTime_UTC5 < fo.ReceiptTime
THEN ffs.FirstScanTime_UTC5
ELSE fo.ReceiptTime
END,
fs.FirstQualifiedTime_UTC5
)) AS AssessmentBaseDate,
CASE
WHEN fs.FirstQualifiedTime_UTC5 IS NOT NULL AND fo.HasLabel = 1
THEN CASE
WHEN HOUR(GREATEST(
CASE
WHEN ffs.FirstScanTime_UTC5 IS NOT NULL
AND ffs.FirstScanTime_UTC5 < fo.ReceiptTime
THEN ffs.FirstScanTime_UTC5
ELSE fo.ReceiptTime
END,
fs.FirstQualifiedTime_UTC5
)) < 16
THEN DATE_ADD(
DATE_ADD(DATE(GREATEST(
CASE
WHEN ffs.FirstScanTime_UTC5 IS NOT NULL
AND ffs.FirstScanTime_UTC5 < fo.ReceiptTime
THEN ffs.FirstScanTime_UTC5
ELSE fo.ReceiptTime
END,
fs.FirstQualifiedTime_UTC5
)), INTERVAL 1 DAY),
INTERVAL 16 HOUR
)
ELSE DATE_ADD(
DATE_ADD(DATE(GREATEST(
CASE
WHEN ffs.FirstScanTime_UTC5 IS NOT NULL
AND ffs.FirstScanTime_UTC5 < fo.ReceiptTime
THEN ffs.FirstScanTime_UTC5
ELSE fo.ReceiptTime
END,
fs.FirstQualifiedTime_UTC5
)), INTERVAL 1 DAY),
INTERVAL '23:59:59' HOUR_SECOND
)
END
ELSE NULL
END AS AssessmentTime,
DATE(CASE
WHEN fs.FirstQualifiedTime_UTC5 IS NOT NULL AND fo.HasLabel = 1
THEN DATE_ADD(DATE(GREATEST(
CASE
WHEN ffs.FirstScanTime_UTC5 IS NOT NULL
AND ffs.FirstScanTime_UTC5 < fo.ReceiptTime
THEN ffs.FirstScanTime_UTC5
ELSE fo.ReceiptTime
END,
fs.FirstQualifiedTime_UTC5
)), INTERVAL 1 DAY)
ELSE NULL
END) AS AssessmentDate,
sa.FirstSuccessTime_UTC5,
sa.FirstSuccessDate_UTC5,
COALESCE(sa.IsSuccess, 0) AS IsSuccess,
COALESCE(sa.IsStopLabel, 0) AS IsStopLabel,
0 AS IsCompletedInAssessment
FROM tmp_form_order fo
INNER JOIN tmp_form_stats fs ON fo.FormId = fs.FormId
LEFT JOIN tmp_form_first_scan ffs ON fo.FormId = ffs.FormId
LEFT JOIN tmp_scan_agg sa ON fo.NeutralWaybillNumber = sa.NeutralWaybillNumber
WHERE fo.HasLabel = 1;
UPDATE tmp_order_full
SET IsCompletedInAssessment = 1
WHERE AssessmentTime IS NOT NULL
AND IsSuccess = 1
AND FirstSuccessTime_UTC5 <= AssessmentTime;
DROP TEMPORARY TABLE IF EXISTS tmp_form_first_scan;
DROP TEMPORARY TABLE IF EXISTS tmp_form_stats;
DROP TEMPORARY TABLE IF EXISTS tmp_form_order;
DROP TEMPORARY TABLE IF EXISTS tmp_scan_agg;
-- ================================================================
-- 步骤6构建 tmp_daily_metrics 的日期维度
-- 从 tmp_order_full 和 tmp_daily_scan 收集所有出现过的日期
-- ================================================================
CREATE TEMPORARY TABLE tmp_daily_metrics (
DATE NOT NULL,
INT NOT NULL DEFAULT 0,
INT NOT NULL DEFAULT 0,
INT NOT NULL DEFAULT 0,
INT NOT NULL DEFAULT 0,
`24H完成数` INT NOT NULL DEFAULT 0,
PRIMARY KEY ()
);
INSERT IGNORE INTO tmp_daily_metrics ()
SELECT DISTINCT ReceiptDate FROM tmp_order_full WHERE ReceiptDate IS NOT NULL
UNION
SELECT DISTINCT LabelRetrievedDate_UTC5 FROM tmp_order_full WHERE LabelRetrievedDate_UTC5 IS NOT NULL
UNION
SELECT DISTINCT FirstSuccessDate_UTC5 FROM tmp_order_full WHERE FirstSuccessDate_UTC5 IS NOT NULL
UNION
SELECT DISTINCT AssessmentBaseDate FROM tmp_order_full WHERE AssessmentBaseDate IS NOT NULL
UNION
SELECT DISTINCT AssessmentDate FROM tmp_order_full WHERE AssessmentDate IS NOT NULL
UNION
SELECT DISTINCT FROM tmp_daily_scan;
-- ================================================================
-- 步骤7按日期聚合各项指标无 CROSS JOIN均为有索引的 GROUP BY
-- ================================================================
-- 当天新增换单数
UPDATE tmp_daily_metrics dm
INNER JOIN (
SELECT ReceiptDate AS , COUNT(DISTINCT RequestId) AS cnt
FROM tmp_order_full
WHERE ReceiptDate IS NOT NULL
GROUP BY ReceiptDate
) t ON dm. = t.
SET dm. = t.cnt;
-- 当日标签推送数
UPDATE tmp_daily_metrics dm
INNER JOIN (
SELECT LabelRetrievedDate_UTC5 AS , COUNT(DISTINCT RequestId) AS cnt
FROM tmp_order_full
WHERE LabelRetrievedDate_UTC5 IS NOT NULL
GROUP BY LabelRetrievedDate_UTC5
) t ON dm. = t.
SET dm. = t.cnt;
-- 当天应该换单数 + 24H完成数
-- 一个订单的 AssessmentBaseDate 和 AssessmentDate 可能不同BaseDate=TAssessmentDate=T+1
-- 该订单在 T 和 T+1 两天都应被计入"当天应该换单数"
-- 使用 UNION 展开两个日期维度后去重统计
CREATE TEMPORARY TABLE tmp_should_replace_dedup (
DATE NOT NULL,
INT NOT NULL DEFAULT 0,
`24H完成数` INT NOT NULL DEFAULT 0,
PRIMARY KEY ()
);
INSERT INTO tmp_should_replace_dedup
SELECT
d.,
COUNT(DISTINCT ofu.RequestId) AS ,
COUNT(DISTINCT CASE
WHEN ofu.IsCompletedInAssessment = 1
AND ofu.FirstSuccessDate_UTC5 = d.
THEN ofu.RequestId END) AS `24H完成数`
FROM (
SELECT DISTINCT AssessmentBaseDate AS FROM tmp_order_full WHERE AssessmentBaseDate IS NOT NULL
UNION
SELECT DISTINCT AssessmentDate AS FROM tmp_order_full WHERE AssessmentDate IS NOT NULL
) d
INNER JOIN tmp_order_full ofu
ON ofu.AssessmentTime IS NOT NULL
AND (ofu.AssessmentBaseDate = d. OR ofu.AssessmentDate = d.)
AND (ofu.IsSuccess = 0 OR ofu.FirstSuccessDate_UTC5 <= d.)
GROUP BY d.;
UPDATE tmp_daily_metrics dm
INNER JOIN tmp_should_replace_dedup srd ON dm. = srd.
SET
dm. = srd.,
dm.`24H完成数` = srd.`24H完成数`;
DROP TEMPORARY TABLE IF EXISTS tmp_should_replace_dedup;
-- 累计要换的总单数
-- 每个订单的计入区间:[MAX(LabelRetrievedDate_UTC5, RequestCreatedDate_UTC5), FirstSuccessDate_UTC5-1 或无穷]
-- 对每个日期 dcount 满足 start_date <= d AND (无成功 OR success_date > d) 的订单数
-- 利用 tmp_daily_metrics × tmp_order_full JOIN但 tmp_order_full 已建索引,
-- 数据量:日期数 × 订单数远小于原来的 CROSS JOINOrderFullInfo 是完整订单,现在只取有标签的)
UPDATE tmp_daily_metrics dm
INNER JOIN (
SELECT
dm2.,
COUNT(DISTINCT ofu.RequestId) AS cnt
FROM tmp_daily_metrics dm2
INNER JOIN tmp_order_full ofu
ON ofu.HasLabel = 1
AND ofu.LabelRetrievedDate_UTC5 <= dm2.
AND ofu.RequestCreatedDate_UTC5 <= dm2.
AND (ofu.IsSuccess = 0 OR ofu.FirstSuccessDate_UTC5 > dm2.)
GROUP BY dm2.
) t ON dm. = t.
SET dm. = t.cnt;
-- ================================================================
-- 最终输出
-- ================================================================
SELECT
dm.,
dm.,
dm.,
dm.,
COALESCE(ds., 0) AS ,
COALESCE(ds., 0) AS ,
COALESCE(ds.STOP数, 0) AS STOP数,
dm.`24H完成数` AS 24,
dm.,
COALESCE(ds., 0) AS ,
CASE
WHEN dm. = 0 THEN '0.00%'
ELSE CONCAT(ROUND(COALESCE(ds., 0) / dm. * 100, 2), '%')
END AS ,
CASE
WHEN dm. = 0 THEN '0.00%'
ELSE CONCAT(ROUND(dm.`24H完成数` / dm. * 100, 2), '%')
END AS 24,
(UTC_TIMESTAMP() - INTERVAL 5 HOUR) AS UTC_5
FROM tmp_daily_metrics dm
LEFT JOIN tmp_daily_scan ds ON dm. = ds.
ORDER BY dm. DESC;
-- ================================================================
-- 清理临时表
-- ================================================================
DROP TEMPORARY TABLE IF EXISTS tmp_daily_scan;
DROP TEMPORARY TABLE IF EXISTS tmp_order_full;
DROP TEMPORARY TABLE IF EXISTS tmp_daily_metrics;
END$$
DELIMITER ;