2016-12-06 52 views
2

比方說,我有一個表外部WHERE子句如何影響嵌套查詢的執行方式?

b | a 
----------- 
17 7000 
17 0 
18 6000 
18 0 
19 5000 
19 2500 

我希望得到一個函數的正值:(a1 - a2) \ (b2 - b1)在笛卡爾積的所有元素的不同B的。 (如果你有興趣,這將導致y1 = b1*x + a1y2 = b2*x + a2交叉口)

我寫QUERY1爲事業

SELECT temp.point FROM 
    (SELECT DISTINCT ((l1.a - l2.a)/(l2.b - l1.b)) AS point 
    FROM lines AS l1 
    CROSS JOIN lines AS l2 
    WHERE l1.b != l2.b 
    ) AS temp 
WHERE temp.point > 0 

它「被零除」錯誤拋出一個。我想同樣的查詢,而WHERE子句(QUERY2)和它工作得很好

SELECT temp.point FROM 
    (SELECT DISTINCT ((l1.a - l2.a)/(l2.b - l1.b)) AS point 
    FROM lines AS l1 
    CROSS JOIN lines AS l2 
    WHERE l1.b != l2.b 
    ) AS temp 

以及與定義的SQL函數(QUERY3

CREATE FUNCTION get_point(@a1 DECIMAL(18, 4), @a2 DECIMAL(18, 4), @b1 INT, @b2 INT) 
RETURNS DECIMAL(18, 4) 
WITH EXECUTE AS CALLER 
AS 
BEGIN 
    RETURN (SELECT (@a1 - @a2)/(@b2 - @b1)) 
END 
GO 
SELECT temp.point FROM 
    (SELECT DISTINCT dbo.get_point(l1.a, l2.a, l1.b, l2.b) AS point 
    FROM lines AS l1 
    CROSS JOIN lines AS l2 
    WHERE l1.b != l2.b 
    ) AS temp 
WHERE temp.point > 0 

我有變化一個直觀的假設,即外層SELECT不應該影響嵌套SELECT的方式(或者至少不應該打破它)。即使這不是真的,也不能解釋爲什麼查詢3工作時查詢1不。

有人可以解釋這背後的原理嗎?這將非常感激。

回答

2

如果你想保證查詢將總是工作,你需要換你的計算中像一個case聲明

case when l2.b - l1.b = 0 
    then null 
    else (l1.a - l2.a)/(l2.b - l1.b) 
end 

技術上,優化是完全免費的,以評估任何順序條件它預計會更有效率。優化程序可以自由地評估where子句之前的除法,該子句可過濾出除數爲0的行。也可以先評估0​​子句。您的不同查詢具有不同的查詢計劃,這會導致不同的行爲。

儘管現實情況下,即使某個查詢今天可能具有「良好」的查詢計劃,但並不能保證優化程序不會在一天,一個月或一年內決定將查詢計劃更改爲這會導致除數爲0的錯誤。我想你可以決定使用一些提示/計劃指南來強制一個特定的計劃,使用特定的行爲。但是這往往是後來在後面叮咬你的那種東西。在case中包含計算(或以其他方式防止除以0錯誤)將會更安全,更容易向下一個開發人員解釋。

+0

謝謝,現在一切都有意義 – ablclanmarazm