SQL查询如何合并空白行,按DispatchNote提取首个有效跟踪号?
SQL需求解决:合并DispatchNote行并修复筛选空值问题
核心问题分析
- 筛选后返回空值:原查询将
B.MLineShipDate的筛选条件放在WHERE中,导致LEFT JOIN退化为INNER JOIN——因为LEFT JOIN后B表字段可能为NULL,而NULL无法满足>=的条件,最终过滤掉了所有A表符合条件但B表无匹配的行。 - 合并多行结果:每个
DispatchNote对应多行,需合并为一行,提取唯一有效的MStockCode和首个有效跟踪号。
修复后的SQL实现
方案一:GROUP BY + 聚合函数(简洁高效)
SELECT A.DispatchNote, MAX(B.MStockCode) AS MStockCode, -- 自动忽略NULL,取唯一非空的库存编码 -- 提取首个有效跟踪号,以下示例假设有效跟踪号是含数字的行,可根据实际格式调整 MIN(CASE WHEN B.NComment LIKE '%[0-9]%' THEN B.NComment END) AS FirstTrackingNumber FROM MdnMaster A LEFT JOIN MdnDetail B ON A.DispatchNote = B.DispatchNote -- 将B表的日期筛选移至JOIN条件,避免过滤A表有效行 AND B.MLineShipDate >= DATEADD(DAY, -4, CAST(GETDATE() AS DATE)) WHERE A.Customer = 'LAWSON' GROUP BY A.DispatchNote;
方案二:窗口函数(更灵活的排序控制)
如果需要严格控制“首个跟踪号”的排序规则(比如按发货日期排序),可以用窗口函数标记行号后筛选:
WITH RankedDetails AS ( SELECT A.DispatchNote, B.MStockCode, B.NComment, -- 按DispatchNote分组,优先取有MStockCode的行,再按发货日期排序 ROW_NUMBER() OVER ( PARTITION BY A.DispatchNote ORDER BY CASE WHEN B.MStockCode IS NOT NULL THEN 0 ELSE 1 END, B.MLineShipDate ) AS RowNum FROM MdnMaster A LEFT JOIN MdnDetail B ON A.DispatchNote = B.DispatchNote AND B.MLineShipDate >= DATEADD(DAY, -4, CAST(GETDATE() AS DATE)) WHERE A.Customer = 'LAWSON' ) SELECT DispatchNote, -- 取整个组内的MStockCode(因为只有一行有值) MAX(MStockCode) OVER (PARTITION BY DispatchNote) AS MStockCode, NComment AS FirstTrackingNumber FROM RankedDetails WHERE RowNum = 1;
关键说明
- 筛选条件调整:将
B.MLineShipDate的条件移至LEFT JOIN的ON子句,确保A表中符合Customer='LAWSON'的行不会被过滤。 - MStockCode提取:用
MAX(B.MStockCode)是因为每个DispatchNote仅一行有值,其余为NULL,聚合函数会自动忽略NULL取有效值。 - 跟踪号提取:示例中用
LIKE '%[0-9]%'判断有效跟踪号,实际需根据NComment的格式调整(比如分隔符、固定前缀等),可结合CHARINDEX、SUBSTRING或STRING_SPLIT函数精准提取。
内容的提问来源于stack exchange,提问作者majinvegito123
相关产品推荐
相关产品推荐

