SQL筆記:SUBSTRING之錯誤訊息誤導?(其實是自己誤解)

今早某隻程式突然報錯,錯誤是來自SQL的標準錯誤訊息「將 nvarchar 值 'XX' 轉換成資料類型 int 時,轉換失敗。」,顯而易見的就是可能發生轉型時的失敗,經過追查後才發現案情並不單純,因此將這個問題記錄在此供給日後參考。

錯誤訊息的起始

以下是報錯的SQL指令,很單純:

SELECT
  *
FROM
  TestView
WHERE
  SUBSTRING(cCode, 5, 1) <> 5

吐出錯誤訊息如下,很顯然的就是第五個字元出現不可自動轉型成數字的問題,理論上只要修正成字元比對模式「'5'」即可。

將 nvarchar 值 'X' 轉換成資料類型 int 時,轉換失敗。

但,調查下去發現案情並不單純...

檢視表VIEW中,並沒有那筆資料?

把檢視表中「所有資料」查找一次,發現根本沒有錯誤訊息指出的'X'字元,阿是在報錯三小?

SELECT
  *
FROM
  TestView
iSN cCode     bState
1   12345678  1
2   22345678  1
4   42345678  1

經過東翻西找後,確定並不是語法問題而是在SQL自己本身查詢的機制,以下是TestView的產生指令,從指令中可以發現是以JOIN的方式來生成:

SELECT
  dbo.TestTable.iSN, dbo.TestTable.cCode, dbo.TestState.bState
FROM
  dbo.TestTable
  INNER JOIN
    dbo.TestState
    ON
    dbo.TestTable.iSN = dbo.TestState.iSN
WHERE
  dbo.TestState.bState = 1

再往下追TestTable資料表,就發現兇手了:

SELECT
  *
FROM
  TestTable
iSN cCode
1   12345678
2   22345678
3   3234X678 << 兇手在此
4   42345678

心得

若檢視表有使用到JOIN指令,當我們針對檢視表進行WHERE查詢時,SQL的動作未必如我們想像中是「先針對」VIEW產生「結果」,再基於這個結果去進行查詢動作。我們可以從下圖「顯示估計執行計畫」中看到,SQL的確把SUBSTRING的指令放到TestTable中查找。

SQL Command Select Substring NoData ErrorData