如何查询不含FiredAlways炉灶的发票中总价第二低的记录
解决未销售FiredAlways炉灶发票中总价第二低的问题
看起来你现在卡在了如何从未包含FiredAlways类型炉灶的发票里拿到总价第二低的记录,我来帮你调整SQL代码,提供几种可行的方案:
先明确核心逻辑:筛选符合条件的发票
首先要确保我们筛选的发票是完全没有销售FiredAlways炉灶的,原来的EXISTS子查询逻辑可能有问题,正确的筛选应该是:
SELECT I.InvoiceNbr, I.InvoiceDt, I.TotalPrice FROM INVOICE I WHERE NOT EXISTS ( -- 检查该发票是否存在任何FiredAlways类型的炉灶行项 SELECT 1 FROM INV_LINE_ITEM li JOIN STOVE s ON li.FK_StoveNbr = s.SerialNumber WHERE li.FK_InvoiceNbr = I.InvoiceNbr AND s.Type = 'FiredAlways' )
这段代码会先过滤出所有从未卖过FiredAlways炉灶的发票,接下来在此基础上获取第二低的总价记录。
方案1:使用OFFSET-FETCH(SQL Server 2012+ 推荐)
这是最简洁直观的方式,先按总价升序排序,跳过第1条(最低的),然后取第1条就是第二低的:
SELECT I.InvoiceNbr, I.InvoiceDt, I.TotalPrice FROM INVOICE I WHERE NOT EXISTS ( SELECT 1 FROM INV_LINE_ITEM li JOIN STOVE s ON li.FK_StoveNbr = s.SerialNumber WHERE li.FK_InvoiceNbr = I.InvoiceNbr AND s.Type = 'FiredAlways' ) ORDER BY I.TotalPrice ASC OFFSET 1 ROW FETCH NEXT 1 ROW ONLY;
如果有多个发票总价相同且都是第二低的(比如最低是100,有两个150的),这个方法只会返回其中一条;如果想返回所有并列第二低的,把FETCH NEXT 1 ROW ONLY改成FETCH NEXT 0 ROWS WITH TIES即可。
方案2:排除最低总价后取最低(兼容旧版SQL Server)
如果你的SQL Server版本低于2012,不支持OFFSET,可以用这个方法:先找到符合条件的发票中的最低总价,然后筛选出总价大于这个值的发票,再取其中最低的,也就是第二低的:
SELECT TOP 1 I.InvoiceNbr, I.InvoiceDt, I.TotalPrice FROM INVOICE I WHERE NOT EXISTS ( SELECT 1 FROM INV_LINE_ITEM li JOIN STOVE s ON li.FK_StoveNbr = s.SerialNumber WHERE li.FK_InvoiceNbr = I.InvoiceNbr AND s.Type = 'FiredAlways' ) AND I.TotalPrice > ( -- 先获取符合条件的发票中的最低总价 SELECT MIN(TotalPrice) FROM INVOICE I2 WHERE NOT EXISTS ( SELECT 1 FROM INV_LINE_ITEM li2 JOIN STOVE s2 ON li2.FK_StoveNbr = s2.SerialNumber WHERE li2.FK_InvoiceNbr = I2.InvoiceNbr AND s2.Type = 'FiredAlways' ) ) ORDER BY I.TotalPrice ASC;
同样,如果要返回所有并列第二低的,把TOP 1改成TOP 1 WITH TIES。
方案3:使用窗口函数(灵活处理排名)
用DENSE_RANK()或者ROW_NUMBER()窗口函数来给符合条件的发票按总价排名,然后取排名为2的记录:
WITH RankedInvoices AS ( SELECT I.InvoiceNbr, I.InvoiceDt, I.TotalPrice, -- 用DENSE_RANK会把相同总价的发票排同一名,ROW_NUMBER则每个发票唯一排名 DENSE_RANK() OVER (ORDER BY I.TotalPrice ASC) AS PriceRank FROM INVOICE I WHERE NOT EXISTS ( SELECT 1 FROM INV_LINE_ITEM li JOIN STOVE s ON li.FK_StoveNbr = s.SerialNumber WHERE li.FK_InvoiceNbr = I.InvoiceNbr AND s.Type = 'FiredAlways' ) ) SELECT InvoiceNbr, InvoiceDt, TotalPrice FROM RankedInvoices WHERE PriceRank = 2;
- 如果用
ROW_NUMBER():即使有多个发票总价相同,每个都会有不同的排名,只会返回其中一条; - 如果用
DENSE_RANK():所有总价相同的第二低发票都会被返回,适合需要并列结果的场景。
注意点
- 请确保你的表之间的关联字段(
FK_InvoiceNbr、FK_StoveNbr、SerialNumber)是正确关联的,避免数据筛选错误; - 如果符合条件的发票数量少于2条,这些查询会返回空结果,你可以根据业务需求添加处理逻辑。
内容的提问来源于stack exchange,提问作者rgo
相关产品推荐
相关产品推荐

