解決 SQL Server 2008 WHERE 子句中的 CASE 語句問題
在 SQL Server 2008 的 WHERE 子句中使用 CASE 語句可能會帶來困難。 以下查詢舉例說明了一個常見問題:
<code class="language-sql">SELECT tl.storenum 'Store #', co.ccnum 'FuelFirst Card #', co.dtentered 'Date Entered', CASE st.reasonid WHEN 1 THEN 'Active' WHEN 2 THEN 'Not Active' WHEN 0 THEN st.ccstatustypename ELSE 'Unknown' END 'Status', CASE st.ccstatustypename WHEN 'Active' THEN ' ' WHEN 'Not Active' THEN ' ' ELSE st.ccstatustypename END 'Reason', UPPER(REPLACE(REPLACE(co.personentered,'RT\\',''),'RACETRAC\\','')) 'Person Entered', co.comments 'Comments or Notes' FROM comments co INNER JOIN cards cc ON co.ccnum=cc.ccnum INNER JOIN customerinfo ci ON cc.customerinfoid=ci.customerinfoid INNER JOIN ccstatustype st ON st.ccstatustypeid=cc.ccstatustypeid INNER JOIN customerstatus cs ON cs.customerstatuscd=ci.customerstatuscd INNER JOIN transactionlog tl ON tl.transactionlogid=co.transactionlogid LEFT JOIN stores s ON s.StoreNum = tl.StoreNum WHERE CASE LEN('TestPerson') WHEN 0 THEN co.personentered = co.personentered ELSE co.personentered LIKE '%TestPerson' END AND cc.ccnum = CASE LEN('TestFFNum') WHEN 0 THEN cc.ccnum ELSE 'TestFFNum' END AND CASE LEN('2011-01-09 11:56:29.327') WHEN 0 THEN co.DTEntered = co.DTEntered ELSE CASE LEN('2012-01-09 11:56:29.327') WHEN 0 THEN co.DTEntered >= '2011-01-09 11:56:29.327' ELSE co.DTEntered BETWEEN '2011-01-09 11:56:29.327' AND '2012-01-09 11:56:29.327' END END AND tl.storenum < 699 ORDER BY tl.StoreNum</code>
解:用布林邏輯重構
核心問題在於 WHERE 子句的條件邏輯中直接使用了 CASE 語句。 CASE 表達式應該產生一個值;它們不應該是全部情況。
解決方案涉及使用 AND
和 OR
運算子將 CASE 語句替換為等效的布林邏輯:
<code class="language-sql">SELECT tl.storenum 'Store #', co.ccnum 'FuelFirst Card #', co.dtentered 'Date Entered', CASE st.reasonid WHEN 1 THEN 'Active' WHEN 2 THEN 'Not Active' WHEN 0 THEN st.ccstatustypename ELSE 'Unknown' END 'Status', CASE st.ccstatustypename WHEN 'Active' THEN ' ' WHEN 'Not Active' THEN ' ' ELSE st.ccstatustypename END 'Reason', UPPER(REPLACE(REPLACE(co.personentered,'RT\\',''),'RACETRAC\\','')) 'Person Entered', co.comments 'Comments or Notes' FROM comments co INNER JOIN cards cc ON co.ccnum=cc.ccnum INNER JOIN customerinfo ci ON cc.customerinfoid=ci.customerinfoid INNER JOIN ccstatustype st ON st.ccstatustypeid=cc.ccstatustypeid INNER JOIN customerstatus cs ON cs.customerstatuscd=ci.customerstatuscd INNER JOIN transactionlog tl ON tl.transactionlogid=co.transactionlogid LEFT JOIN stores s ON s.StoreNum = tl.StoreNum WHERE (LEN('TestPerson') = 0 AND co.personentered = co.personentered) OR (LEN('TestPerson') > 0 AND co.personentered LIKE '%TestPerson') AND ((LEN('TestFFNum') = 0 AND cc.ccnum = cc.ccnum) OR (LEN('TestFFNum') > 0 AND cc.ccnum = 'TestFFNum')) AND ((LEN('2011-01-09 11:56:29.327') = 0 AND co.DTEntered = co.DTEntered) OR (LEN('2012-01-09 11:56:29.327') = 0 AND co.DTEntered >= '2011-01-09 11:56:29.327') OR (co.DTEntered BETWEEN '2011-01-09 11:56:29.327' AND '2012-01-09 11:56:29.327')) AND tl.storenum < 699 ORDER BY tl.StoreNum;</code>
效能增強
雖然這個更正後的查詢可以正確運行,但效能還可以進一步提高:
OR
條件可能會降低效率。 考慮替代查詢結構(例如,使用 UNION ALL
表示不同的搜尋條件)。 WHERE
子句中經常使用的欄位上有索引(例如 co.personentered
、cc.ccnum
、co.DTEntered
、tl.storenum
)。 透過解決這些問題,您可以建立更有效率且可讀的 SQL 查詢。
以上是如何在SQL Server 2008中正確使用WHERE子句中的CASE語句?的詳細內容。更多資訊請關注PHP中文網其他相關文章!