2013-07-15 26 views
2

我有兩個表。SQL沒有正確識別和遵守WHERE語句

DECLARE @definitions TABLE 
(fDefId varchar(8) , 
    dType varchar(MAX) , 
    fName varchar(MAX) 
) 

INSERT @definitions values('8c7eab0e','string','custpartno') 
INSERT @definitions values('8c7eab02','int' ,'itemno' ) 

DECLARE @fields TABLE 
(rowId varchar(8) , 
    fkFId varchar(8) , 
    adj varchar(MAX) 
) 

INSERT @fields values('83EDE211','8c7eab0e','89319971151801') 
INSERT @fields values('83EDE211','8c7eab02','1'   ) 

我試圖找到記錄@fields當值不是int並在@definitions表中的相關記錄有'int'一個dType值。

當我試圖得到結果的這個列表(如果有的話),我想這些語句:

SELECT f.rowId , 
     f.fkFId , 
     f.adj , 
     d.fName 
    FROM @fields  f 
    JOIN @definitions d ON f.fkFId = d.fDefId 
         AND d.dType = 'int' 
    WHERE ISNUMERIC(adj  ) <> 1 
    OR CAST(  adj AS INT) <> adj 

SELECT * 
FROM (SELECT f.rowId , 
       f.fkFId , 
       f.adj , 
       d.fName 
     FROM @fields  f 
     JOIN @definitions d ON f.fkFId = d.fDefId 
          AND d.dType='int' 
    ) a 
WHERE ISNUMERIC(adj  ) <> 1 
    OR CAST(  adj AS INT) <> adj 

,並得到這個錯誤有兩個:

The conversion of the varchar value '89319971151801' overflowed an int column. 

然而,當我第一家店表格變量的值如下:

DECLARE @temp TABLE 
(rowId varchar(8), 
    fDefId varchar(8), 
    adjusted varchar(MAX) 
) 

INSERT @temp 
SELECT f.rowId , 
     f.fkFId , 
     f.adj 
FROM @fields  f 
JOIN @definitions d ON f.fkFId = d.fDefId 
        AND d.dType = 'int' 

SELECT * FROM @temp 
WHERE ISNUMERIC(adjusted  ) <> 1 
    OR CAST(  adjusted AS INT) <> adjusted 

我得到了預期的結果(本例中沒有記錄)。

如果我刪除WHERE條款我得到這些結果:

enter image description here

與大場行是不存在的,所以它爲什麼會加入WHERE後造成的錯誤?

我也能避免這個問題通過鑄塑BIGINT代替INT,但爲什麼會因爲JOINWHERE條款此事刪除,是不是從一開始的INT價值?

回答

1

您知道SQL標準沒有要求特定的表達式評估順序或表達式評估的短路嗎?只要保持語義含義(不是意圖),查詢優化器可以自由地重新排列整個查詢。

你的事情第二刺,在datetype = 'int'預過濾和加載過濾的結果的作品,因爲它強制運行的查詢處理器的訂單。

你單查詢嘗試失敗,因爲表達

CAST(adj AS INT) <> adj 

其中

  • 需要varchar
  • 將其轉換爲int
  • 轉換是int回一個varchar,和終於...
  • 比較varchar(包含int的歸一化/規範字符串表示形式)回到原始varchar值。

失敗。它失敗了,因爲查詢處理器必須評估每個候選行的表達式,而不管列datatype是否包含int

第二次單個查詢嘗試與from子句中的派生表失敗,因爲優化程序足夠智能以查看可重構查詢以便不使用派生表。

當然,真正的問題是你有一個非規範化的數據庫設計,並且你超載了列adj的含義(和數據類型),試圖讓一個表成爲多個事物。

+0

我一直認爲WHERE子句是作爲一個整體來評估的。我不知道它會/可能一次完成一部分。 – davids

+0

我們不得不使用這種設計來實現我們應用程序的這一部分所需的結果。它用於從文本文件導入記錄,我們需要跟蹤和顯示每個字段和值的元信息,並允許來回擺動。我們還可以輕鬆地將其他字段添加到導入過程。 – davids

+0

我猜測那最後一種方法實際上對我來說是最好的,因爲它會減少評估它是否是'int'的記錄數。這是真的,還是考慮到設計限制,有更好的方法嗎? – davids