2017-04-04 95 views
8

我正在使用通過ODBC連接的MSSQL數據庫。PDO :: bindValue()在嵌套SELECT查詢時失敗

在具有嵌套SELECT語句的查詢上使用PDO::bindValue()時,它無法在嵌套SELECT內綁定值(主SELECT中沒有問題)。 這是一段示例代碼失敗:

$stmt = $cmdb->prepare("SELECT ci.CI FROM dbo.cmdb_ci AS ci " . 
         "INNER JOIN dbo.cmdb_model AS m ON m.ModelID = ci.Modelid " . 
         "INNER JOIN dbo.cmdb_class AS c ON c.ClassID = m.Classid " . 
         "WHERE (c.ClassID = :classid) " . 
         "AND (ci.CI IN (SELECT ci2.CI " . 
             "FROM dbo.cmdb_ci AS ci2 " . 
             "INNER JOIN dbo.cmdb_ci_status AS st2 ON st2.CI = ci2.CI " . 
             "WHERE st2.LocationID = :locationid))"); 
$stmt->bindValue("classid", 13); 
$stmt->bindValue("locationid", 1011); 
$stmt->execute(); 
if ($rows = $stmt->fetchAll()) 
    $stmt->closeCursor(); 
foreach ($rows as $row) 
    echo $row["CI"]; 

我得到的錯誤是:

SQLSTATE [22018]:用於鑄鐵規範無效字符值:206 [微軟] [SQL Server本機客戶端11.0] [SQL服務器]操作數類型衝突:文本與詮釋不兼容(SQLExecute [206]在/builddir/build/BUILD/php-5.4.16/ext/pdo_odbc/odbc_stmt.c:254)

如果我忽略bindValue()爲「:locationid」和直接在查詢中插入「1011」,調用完成而沒有錯誤並且結果正確。

這是PDO中的錯誤,還是必須以不同的方式調用bindValue()?

+0

是LocationID設定在int或文字的數據庫? – aynber

+1

'$ stmt-> bindValue(「locationid」,1011,PDO :: PARAM_INT);'如錯誤說的那樣,你使用text來投射int。沒有PDO的bindValue:PARAM_變成一個字符串,例如文本。 – JustOnUnderMillions

+0

LocationID被定義爲一個int。 – Dandorid

回答

4

至於(我從評論看)告訴bindValue是傳遞的值是一個整數解決問題...

$stmt->bindValue("locationid", 1011, PDO::PARAM_INT); 

...我認爲出於某種原因(a bug in pdo_odbc ?)無論您在bindValue上指定爲第三個參數,參數都以字符串的形式輸入查詢。

然後,我會建議通過將該值轉換爲整數到位進入查詢。

在最後一行:

"WHERE st2.LocationID = CAST(:locationid, int)))" 

這是不是很優雅,但直到找到PDO_ODBC


修復/補丁如果連這不起作用可能是合適的還有一個更不雅的解決方案(當然是作爲臨時解決方案)。

您寫道:

如果我離開了bindValue()用於「:locationid」,插入「1011」直接進入查詢,呼叫完成,沒有錯誤,並用正確的結果。

因此,您可以將位置ID直接放入查詢中。

假設位置ID被存儲到$locationId那麼查詢的最後一行變爲:

"WHERE st2.LocationID = $locationId))"); 

由於這是容易發生SQL注入$locationId必須被消毒(或驗證)預先。

值必須爲正整數所以不是逃避它,我建議更容易和防彈辦法:檢查$locationId僅由數字...

if(! ctype_digit((string) $locationId)) { 
    // location id is invalid 
    // do not proceed ! 
} 
1

難道它的位置ID實際上是作爲一個字符串存儲在MSSQL而不是一個int?當你添加引號時它有效嗎? $ stmt-> bindValue(「locationid」,「1011」,PDO :: PARAM_STR);

+0

的穩定版本不,這不起作用,因爲LocationID值被定義爲INT(見上文),所以這會使其成爲無效的SQL語句。 – Dandorid