CASE表达式无返回行时如何显示指定值?SQL查询求助
我来帮你搞定这个问题!你的核心需求很明确:不管R5TRANSLINES里有没有符合条件的行,都得返回一行结果,ORG固定是'198'(或者你更新代码里的'ESREQ1'),SumTotal要么是计算值,要么是NULL/指定默认值。之前的方法没用,是因为当原查询没有匹配行时,整个SELECT根本没有数据源,自然不会输出任何内容——ISNULL这类函数只对已有行的字段生效,没有行的话它们根本没机会发挥作用。
问题根源分析
原代码和你更新后的代码,都是直接从R5TRANSLINES取数计算。如果这个表没有符合条件的记录,整个查询就没有“基础行”,哪怕你用了窗口函数SUM() OVER(),也没法凭空生成一行结果。
解决方案:强制生成一行基础数据
我们可以先构造一个固定的单一行数据源(比如用VALUES (1)生成一个临时行),然后用LEFT JOIN关联你的计算查询。这样哪怕计算查询没有结果,固定的那一行也会保留,再用ISNULL/COALESCE给SumTotal设置默认值就可以了。
方案1:无匹配时返回NULL作为SumTotal
DECLARE @startdate VARCHAR(30); DECLARE @enddate VARCHAR(30); DECLARE @count INT; SET @startdate = '2017-12-01'; SET @enddate = '2018-01-01'; -- 先统计符合条件的行数,和你原逻辑一致 SELECT @count = COUNT(*) FROM R5TRANSLINES WHERE TRL_TYPE = 'STTK' AND TRL_TRANS IN ( SELECT TRA_CODE FROM R5TRANSACTIONS WHERE TRA_FROMCODE IN ('198') AND TRA_STATUS IN ('A') AND TRA_DATE BETWEEN @startdate AND @enddate ); -- 用固定行LEFT JOIN计算结果,确保总有输出 SELECT '198' AS ORG, calc.SumTotal FROM (VALUES (1)) AS dummy(id) -- 这里生成一个固定的单一行 LEFT JOIN ( -- 这里是你原有的计算逻辑,只返回SumTotal字段 SELECT (SUM(CASE WHEN (TRL_ORIGQTY = 0 AND TRL_ORIGQTY > 0) THEN 0 WHEN ((TRL_ORIGQTY - TRL_QTY) = 0 AND TRL_ORIGQTY = 0) THEN 100 WHEN ((TRL_ORIGQTY - TRL_QTY) > TRL_ORIGQTY) THEN ((TRL_ORIGQTY / (TRL_ORIGQTY - TRL_QTY)) * 100) ELSE (((TRL_ORIGQTY - TRL_QTY) / TRL_ORIGQTY) * 100) END) OVER () / @count) AS SumTotal FROM R5TRANSLINES WHERE TRL_TYPE = 'STTK' AND TRL_TRANS IN ( SELECT TRA_CODE FROM R5TRANSACTIONS WHERE TRA_FROMCODE IN ('198') AND TRA_STATUS IN ('A') AND TRA_DATE BETWEEN @startdate AND @enddate ) ) AS calc ON 1=1; -- 无条件关联,确保固定行能拿到计算结果(如果有的话)
方案2:无匹配时返回指定默认值(比如0或者'00001')
只需要把上面的calc.SumTotal改成ISNULL(calc.SumTotal, 0)就行,如果要返回字符串'00001',注意类型匹配(比如把0换成'00001'):
DECLARE @startdate VARCHAR(30); DECLARE @enddate VARCHAR(30); DECLARE @count INT; SET @startdate = '2017-12-01'; SET @enddate = '2018-01-01'; SELECT @count = COUNT(*) FROM R5TRANSLINES WHERE TRL_TYPE = 'STTK' AND TRL_TRANS IN ( SELECT TRA_CODE FROM R5TRANSACTIONS WHERE TRA_FROMCODE IN ('198') AND TRA_STATUS IN ('A') AND TRA_DATE BETWEEN @startdate AND @enddate ); SELECT '198' AS ORG, -- 无匹配时返回0,你可以改成'00001'等指定值 ISNULL(calc.SumTotal, 0) AS SumTotal FROM (VALUES (1)) AS dummy(id) LEFT JOIN ( SELECT (SUM(CASE WHEN (TRL_ORIGQTY = 0 AND TRL_ORIGQTY > 0) THEN 0 WHEN ((TRL_ORIGQTY - TRL_QTY) = 0 AND TRL_ORIGQTY = 0) THEN 100 WHEN ((TRL_ORIGQTY - TRL_QTY) > TRL_ORIGQTY) THEN ((TRL_ORIGQTY / (TRL_ORIGQTY - TRL_QTY)) * 100) ELSE (((TRL_ORIGQTY - TRL_QTY) / TRL_ORIGQTY) * 100) END) OVER () / @count) AS SumTotal FROM R5TRANSLINES WHERE TRL_TYPE = 'STTK' AND TRL_TRANS IN ( SELECT TRA_CODE FROM R5TRANSACTIONS WHERE TRA_FROMCODE IN ('198') AND TRA_STATUS IN ('A') AND TRA_DATE BETWEEN @startdate AND @enddate ) ) AS calc ON 1=1;
适配你更新后的代码
如果你需要用更新后的逻辑(ORG为'ESREQ1',条件包含UPPER(TRA_DESC) like '%AUDITESREQ1%'),只需要把代码里的'198'替换成'ESREQ1',并把WHERE子句里的条件换成你更新后的版本就行,核心逻辑完全一致。
为什么之前的ISNULL/NOT EXISTS没用?
ISNULL是对已有行的字段做判断,如果查询没有返回行,它根本没有处理对象;NOT EXISTS如果只是作为查询条件,同样不会生成新行——除非你用UNION ALL把NOT EXISTS的判断结果和原查询合并,但这种方式不如LEFT JOIN固定行简洁。
内容的提问来源于stack exchange,提问作者Piston
相关产品推荐
相关产品推荐

