2014-12-19 93 views
2

在此示例查詢(針對設計拙劣的供應商數據庫):移動IF EXISTS WHERE子句

DECLARE @OrderNo AS CHAR(8) = LEFT(@FullOrderNo,8) 

IF EXISTS (SELECT 1 FROM Foo WHERE FullOrderNumber = @FullOrderNo) 

    SELECT Stuff 
    FROM Foo 
    WHERE X = 'Y' 
      AND FullOrderNumber = @FullOrderNo 

    ELSE 

    SELECT Stuff 
    FROM Foo 
    WHERE X = 'Y' 
      AND OrderNumber = @OrderNo 

由於選擇並在WHERE子句的第一部分是相同的,是有辦法來安全地結合查詢,同時確保首先檢查FullOrderNumber匹配?我看到有no guarantees for WHERE clause evaluation order

+0

'WHERE FullOrderNumber = @FullOrderNo OR OrderNumb er = @ OrderNo' –

+0

@ M.Ali:當存在'FullOrderNumber = @ FullOrderNo'的記錄時,將返回'OrderNumber = @ OrderNo'不需要的記錄 – Gerrat

+0

@ M.Ali我只想在OrderNumber上匹配,如果沒有匹配表中任何地方的FullOrderNumber。 – TrueWill

回答

3

你可以寫爲:

SELECT Stuff 
FROM Foo 
WHERE X = 'Y' AND 
     (FullOrderNumber = @FullOrderNo OR 
     (NOT EXISTS (SELECT 1 FROM Foo WHERE FullOrderNumber = @FullOrderNo) and OrderNumber = @OrderNo)) 

如果你正在尋找只有一排,你可以使用order by爲優先級:

SELECT TOP (1) Stuff 
FROM Foo 
WHERE X = 'Y' AND 
     (FullOrderNumber = @FullOrderNo OR OrderNumber = @OrderNo) 
ORDER BY (CASE WHEN FullOrderNumber = @FullOrderNo THEN 1 ELSE 2 END) 

其實,即使有重複的,你可以使用with ties這樣的:

SELECT TOP (1) WITH TIES Stuff 
FROM Foo 
WHERE X = 'Y' AND 
     (FullOrderNumber = @FullOrderNo OR OrderNumber = @OrderNo) 
ORDER BY (CASE WHEN FullOrderNumber = @FullOrderNo THEN 1 ELSE 2 END) 
+2

這些示例可能會將這兩個語句重新編寫爲一個;但他們不能保證:「首先檢查FullOrderNumber匹配」。如果在FullOrderNumber上有一個索引,但在OrderNumber上沒有索引,則它可能會執行全表掃描(據推測OP正試圖避免滿足此要求)。 – Gerrat

+0

@Gerrat。 。 。我將其解釋爲「完整訂單號碼先返回」。但是,我不太確定OP的含義。 –

+0

@GordonLinoff - 謝謝;爲了澄清,我寧願避免表掃描。如果原始表現更好,我會堅持。 – TrueWill