优化SQL,CASE中同一行多次
Posted
技术标签:
【中文标题】优化SQL,CASE中同一行多次【英文标题】:Optimize SQL, same line multiple times in CASE 【发布时间】:2016-11-29 13:37:36 【问题描述】:我编写了一个 SQL Servre 存储过程 (SQL Server 2014),它查看某个表中的某个列,如果结果为 null,我想从其他列中获取值。
这行我写了两次:
(Select t_EC
from TTCIB
where rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
and t_comp = '50')
检查一次是否为空。
如果它不为空,则第二次将值实际添加到我的结果中。
有没有办法优化这个?这样系统就不需要运行这条线两次了? (它有两次 ltrim 函数和两次 rtrim 函数,所以很有用)
SELECT DISTINCT TOP 15
(SELECT t_EC
FROM TTCIB
WHERE rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
AND t_comp = '18') as EC18,
CASE
WHEN (SELECT t_EC FROM TTCIB
WHERE rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
AND t_comp = '50') IS NULL
THEN (SELECT t_EC
FROM TTCIB
WHERE rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
AND t_comp = '51')
ELSE (SELECT t_EC
FROM TTCIB
WHERE rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
AND t_comp = '50')
END AS EC50,
RTRIM(t1.t_sern) AS SerialNumber, t1.t_item AS Item,
RTRIM(t1.t_desc) AS ItemDesc, t1.t_ofbp AS SoldToBP,
RTRIM(t2.t_nama) AS BPName, t1.t_cwte AS Warranty,
t1.t_dltm AS DeliveryTime, t_optm AS InstallationTime,
t_clst AS Cluster, ISNULL(t3.t_endt,'1970-01-01') AS EndDate,
t4.t_csig as ItemSignalCode, t5.t_dsca as ItemSignalCodeDesc
FROM
FnGetSerialNos(@SerialNumber, @MasterCompany) t1
INNER JOIN
ttccom100900 t2 ON t1.t_ofbp = t2.t_bpid
LEFT OUTER JOIN
ttsctm120900 t3 ON t1.t_term = t3.t_term
LEFT OUTER JOIN
ttcibd001900 t4 ON ltrim(t1.t_item) = ltrim(t4.t_item)
LEFT OUTER JOIN
ttcmcs018900 t5 ON t4.t_csig = t5.t_csig
【问题讨论】:
标记您正在使用的 dbms。 (那里有一些非 ANSI SQL。) 不相关的子查询...您的查询可能会被完全重写。添加一些示例表数据和预期结果 - 以及格式化文本。 查询的其余部分在哪里? 显示正确的数据样本和预期的结果.. 能否也请您发布创建表脚本,它会告诉我们这些列也属于哪个表 【参考方案1】:使用 INNER JOIN 从 TTCIB
读取所有相关值,并使用 COALESCE()
函数而不是 CASE WHEN ... END
:
SELECT DISTINCT TOP 15
x.t_18 as EC18
,COALESCE(x.t_50, x.t_51) AS EC50
,RTRIM(t1.t_sern) AS SerialNumber
,t1.t_item AS Item
,RTRIM(t1.t_desc) AS ItemDesc
,t1.t_ofbp AS SoldToBP
,RTRIM(t2.t_nama) AS BPName
,t1.t_cwte AS Warranty
,t1.t_dltm AS DeliveryTime
,t_optm AS InstallationTime
,t_clst AS Cluster
, ISNULL(t3.t_endt,'1970-01-01') AS EndDate
,t4.t_csig as ItemSignalCode
, t5.t_dsca as ItemSignalCodeDesc
FROM FnGetSerialNos(@SerialNumber, @MasterCompany) t1
INNER JOIN (
SELECT RTRIM(LTRIM(t_EC)) AS t_EC
,MAX(CASE WHEN t_comp = '18' THEN t_EC END) AS t_18
,MAX(CASE WHEN t_comp = '50' THEN t_EC END) AS t_50
,MAX(CASE WHEN t_comp = '51' THEN t_EC END) AS t_51
FROM TTCIB
GROUP BY t_EC
) x
ON RTRIM(LTRIM(t1.t_item)) = x.t_EC
INNER JOIN ttccom100900 t2
ON t1.t_ofbp = t2.t_bpid
LEFT OUTER JOIN ttsctm120900 t3
ON t1.t_term = t3.t_term
Left Outer JOIN ttcibd001900 t4
ON ltrim(t1.t_item) = ltrim(t4.t_item)
Left Outer JOIN ttcmcs018900 t5
ON t4.t_csig = t5.t_csig
;
【讨论】:
【参考方案2】:更快(适用于各种数据库)
coalesce((Select t_EC from TTCIB where rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item)) and t_comp = '50'),(Select t_EC from TTCIB where rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item)) and t_comp = '51')) as EC50
最快(只针对sqlserver,oracle用这种方法比较复杂)
(Select top 1 t_EC from TTCIB where rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item)) and t_comp in ('50','51') order by t_comp asc) as EC50
【讨论】:
以上是关于优化SQL,CASE中同一行多次的主要内容,如果未能解决你的问题,请参考以下文章