-- 客户维度每日标签统计查询(不关联订单表) -- 设计逻辑: -- 1. 基于 label_scan_history、customers 两表关联 -- 2. 统计维度:客户简称、日期、扫描数、换单成功数、换单失败数、STOP数等 WITH -- 步骤1:获取客户信息 CustomerInfo AS ( SELECT c.id AS CustomerId, c.CustomerCode, c.CustomerName FROM customers c WHERE c.Status = 'Y' ), -- 步骤2:关联扫描记录与客户信息 ScanWithCustomer AS ( SELECT s.NeutralWaybillNumber, s.CustomerId AS ScanCustomerId, DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')) AS 扫描日期, s.Result, s.Description, s.CreatedAt AS 扫描时间, c.CustomerCode, c.CustomerName FROM label_scan_history s LEFT JOIN CustomerInfo c ON s.CustomerId = c.CustomerId ), -- 步骤3:获取每个中性面单号的首次成功时间和日期 NeutralWaybillSuccessInfo AS ( SELECT s.NeutralWaybillNumber, MIN(CASE WHEN s.Result = 0 THEN s.CreatedAt ELSE NULL END) AS 首次成功时间, MIN(CASE WHEN s.Result = 0 THEN DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')) ELSE NULL END) AS 首次成功日期 FROM label_scan_history s GROUP BY s.NeutralWaybillNumber ), -- 步骤4:每日扫描数统计(去重)- 有客户简称 DailyScanCount AS ( SELECT CustomerCode, 扫描日期, COUNT(DISTINCT NeutralWaybillNumber) AS 扫描数 FROM ( -- 每个中性面单号每天取最新一条记录 SELECT CustomerCode, NeutralWaybillNumber, 扫描日期, ROW_NUMBER() OVER (PARTITION BY NeutralWaybillNumber, 扫描日期 ORDER BY 扫描时间 DESC) AS rn FROM ScanWithCustomer WHERE CustomerCode IS NOT NULL ) AS t WHERE rn = 1 GROUP BY CustomerCode, 扫描日期 ), -- 步骤5:每日换单成功数统计(去重)- 有客户简称,去除STOP数 DailySuccessCount AS ( SELECT CustomerCode, 扫描日期, COUNT(DISTINCT NeutralWaybillNumber) AS 换单成功数 FROM ( SELECT CustomerCode, NeutralWaybillNumber, 扫描日期, MAX(CASE WHEN Result = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY NeutralWaybillNumber, 扫描日期) AS has_success, MAX(CASE WHEN Result = 0 AND Description LIKE '%STOP%' THEN 1 ELSE 0 END) OVER (PARTITION BY NeutralWaybillNumber, 扫描日期) AS has_stop, ROW_NUMBER() OVER (PARTITION BY NeutralWaybillNumber, 扫描日期 ORDER BY 扫描时间 DESC) AS rn FROM ScanWithCustomer WHERE CustomerCode IS NOT NULL ) AS t WHERE rn = 1 AND has_success = 1 AND has_stop = 0 GROUP BY CustomerCode, 扫描日期 ), -- 步骤6:每日换单失败数统计(去重)- 有客户简称,除去换单成功记录 DailyFailedCount AS ( SELECT CustomerCode, 扫描日期, COUNT(DISTINCT NeutralWaybillNumber) AS 换单失败数 FROM ( SELECT CustomerCode, NeutralWaybillNumber, 扫描日期, MAX(CASE WHEN Result = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY NeutralWaybillNumber, 扫描日期) AS has_success, MAX(CASE WHEN Result != 0 THEN 1 ELSE 0 END) OVER (PARTITION BY NeutralWaybillNumber, 扫描日期) AS has_failure, ROW_NUMBER() OVER (PARTITION BY NeutralWaybillNumber, 扫描日期 ORDER BY 扫描时间 DESC) AS rn FROM ScanWithCustomer WHERE CustomerCode IS NOT NULL ) AS t WHERE rn = 1 AND has_success = 0 GROUP BY CustomerCode, 扫描日期 ), -- 步骤7:每日STOP数统计(去重)- 有客户简称 DailyStopCount AS ( SELECT CustomerCode, 扫描日期, COUNT(DISTINCT NeutralWaybillNumber) AS STOP数 FROM ( SELECT CustomerCode, NeutralWaybillNumber, 扫描日期, MAX(CASE WHEN Result = 0 AND Description LIKE '%STOP%' THEN 1 ELSE 0 END) OVER (PARTITION BY NeutralWaybillNumber, 扫描日期) AS has_stop, ROW_NUMBER() OVER (PARTITION BY NeutralWaybillNumber, 扫描日期 ORDER BY 扫描时间 DESC) AS rn FROM ScanWithCustomer WHERE CustomerCode IS NOT NULL ) AS t WHERE rn = 1 AND has_stop = 1 GROUP BY CustomerCode, 扫描日期 ), -- 步骤8:总无人认领数统计 - CustomerId为0的扫描记录(去重) DailyUnclaimedCount AS ( SELECT 扫描日期, COUNT(DISTINCT NeutralWaybillNumber) AS 总无人认领数 FROM ( SELECT NeutralWaybillNumber, 扫描日期, ROW_NUMBER() OVER (PARTITION BY NeutralWaybillNumber, 扫描日期 ORDER BY 扫描时间 DESC) AS rn FROM ScanWithCustomer WHERE ScanCustomerId = 0 ) AS t WHERE rn = 1 GROUP BY 扫描日期 ), -- 步骤9:总扫描次数统计(不去重) DailyTotalScanCount AS ( SELECT 扫描日期, COUNT(*) AS 总扫描次数 FROM ScanWithCustomer GROUP BY 扫描日期 ), -- 步骤10:收集所有日期 AllDates AS ( SELECT DISTINCT 扫描日期 FROM DailyScanCount UNION SELECT DISTINCT 扫描日期 FROM DailySuccessCount UNION SELECT DISTINCT 扫描日期 FROM DailyFailedCount UNION SELECT DISTINCT 扫描日期 FROM DailyStopCount UNION SELECT DISTINCT 扫描日期 FROM DailyUnclaimedCount UNION SELECT DISTINCT 扫描日期 FROM DailyTotalScanCount ), -- 步骤11:收集所有客户简称 AllCustomers AS ( SELECT DISTINCT CustomerCode FROM DailyScanCount UNION SELECT DISTINCT CustomerCode FROM DailySuccessCount UNION SELECT DISTINCT CustomerCode FROM DailyFailedCount UNION SELECT DISTINCT CustomerCode FROM DailyStopCount ) -- 最终查询结果 SELECT ad.扫描日期 AS 日期, ac.CustomerCode AS 客户简称, COALESCE(dsc.扫描数, 0) AS 扫描数, COALESCE(dsuc.换单成功数, 0) AS 换单成功数, COALESCE(dfac.换单失败数, 0) AS 换单失败数, COALESCE(dstc.STOP数, 0) AS STOP数, -- 换单成功率 CASE WHEN COALESCE(dsc.扫描数, 0) = 0 THEN '0.00%' ELSE CONCAT(ROUND(COALESCE(dsuc.换单成功数, 0) / COALESCE(dsc.扫描数, 0) * 100, 2), '%') END AS 换单成功率, COALESCE(duc.总无人认领数, 0) AS 总无人认领数, COALESCE(dtsc.总扫描次数, 0) AS 总扫描次数, (UTC_TIMESTAMP() - INTERVAL 5 HOUR) AS 数据拉取时间(UTC_5) FROM AllDates ad CROSS JOIN AllCustomers ac LEFT JOIN DailyScanCount dsc ON ad.扫描日期 = dsc.扫描日期 AND ac.CustomerCode = dsc.CustomerCode LEFT JOIN DailySuccessCount dsuc ON ad.扫描日期 = dsuc.扫描日期 AND ac.CustomerCode = dsuc.CustomerCode LEFT JOIN DailyFailedCount dfac ON ad.扫描日期 = dfac.扫描日期 AND ac.CustomerCode = dfac.CustomerCode LEFT JOIN DailyStopCount dstc ON ad.扫描日期 = dstc.扫描日期 AND ac.CustomerCode = dstc.CustomerCode LEFT JOIN DailyUnclaimedCount duc ON ad.扫描日期 = duc.扫描日期 LEFT JOIN DailyTotalScanCount dtsc ON ad.扫描日期 = dtsc.扫描日期 WHERE COALESCE(dsc.扫描数, 0) > 0 ORDER BY ad.扫描日期 DESC, ac.CustomerCode;