PHP Conference Japan 2024

sqlsrv_prepare

(沒有版本資訊,可能僅在 Git 中)

sqlsrv_prepare準備查詢以執行

描述

sqlsrv_prepare(
    resource $conn,
    string $sql,
    array $params = ?,
    array $options = ?
): mixed

準備查詢以執行。此函式非常適合用來準備一個將多次執行且每次具有不同參數值的查詢。

參數

conn

sqlsrv_connect() 傳回的連線資源。

sql

定義要準備和執行的查詢的字串。

params

一個陣列,指定在執行參數化查詢時的參數資訊。陣列元素可以是以下任何一種

  • 一個常值
  • 一個 PHP 變數
  • 一個具有以下結構的陣列:array($value [, $direction [, $phpType [, $sqlType]]])
下表描述上述陣列結構中的元素

陣列結構
元素 描述
$value 一個常值、一個 PHP 變數或一個 PHP 參考變數。
$direction (選用) 下列 SQLSRV 常數之一,用於指示參數方向:SQLSRV_PARAM_IN、SQLSRV_PARAM_OUT、SQLSRV_PARAM_INOUT。預設值為 SQLSRV_PARAM_IN。
$phpType (選用) 指定傳回值 PHP 資料型別的 SQLSRV_PHPTYPE_* 常數。
$sqlType (選用) 指定輸入值 SQL Server 資料型別的 SQLSRV_SQLTYPE_* 常數。
options

一個陣列,指定查詢屬性選項。下表描述了支援的鍵

查詢選項
描述
QueryTimeout 一個正整數值。 設定查詢逾時(以秒為單位)。預設情況下,驅動程式會無限期地等待結果。
SendStreamParamsAtExec truefalse (預設值為 true) 將驅動程式設定為在執行時傳送所有串流資料(true),或以區塊傳送串流資料(false)。預設情況下,該值設定為 true。如需更多資訊,請參閱 sqlsrv_send_stream_data()
Scrollable SQLSRV_CURSOR_FORWARD、SQLSRV_CURSOR_STATIC、SQLSRV_CURSOR_DYNAMIC 或 SQLSRV_CURSOR_KEYSET 請參閱 Microsoft SQLSRV 文件中的 » 指定游標類型並選取資料列

傳回值

成功時傳回語句資源,如果發生錯誤則傳回 false

範例

範例 1:sqlsrv_prepare() 範例

此範例示範如何使用 sqlsrv_prepare() 準備語句,並使用 sqlsrv_execute() 多次重新執行(使用不同的參數值)。

<?php
$serverName
= "serverName\sqlexpress";
$connectionInfo = array( "Database"=>"dbName", "UID"=>"username", "PWD"=>"password");
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if(
$conn === false) {
die(
print_r( sqlsrv_errors(), true));
}

$sql = "UPDATE Table_1
SET OrderQty = ?
WHERE SalesOrderID = ?"
;

// 初始化參數並準備語句。
// 變數 $qty 和 $id 繫結至語句 $stmt。
$qty = 0; $id = 0;
$stmt = sqlsrv_prepare( $conn, $sql, array( &$qty, &$id));
if( !
$stmt ) {
die(
print_r( sqlsrv_errors(), true));
}

// 設定 SalesOrderDetailID 和 OrderQty 資訊。
// 此陣列以 key=>value 配對方式將訂單 ID 對應至訂單數量。
$orders = array( 1=>10, 2=>20, 3=>30);

// 執行每個訂單的語句。
foreach( $orders as $id => $qty) {
// 因為 $id 和 $qty 繫結至 $stmt1,所以每次執行語句時都會使用其更新的值。
if( sqlsrv_execute( $stmt ) === false ) {
die(
print_r( sqlsrv_errors(), true));
}
}
?>

注意

當您準備使用變數作為參數的語句時,變數會繫結至該語句。這表示如果您更新變數的值,下次執行該語句時將會使用更新後的參數值。對於您計劃僅執行一次的語句,請使用 sqlsrv_query()

參見

新增註解

使用者貢獻的註解 2 則註解

4
tuxedobob
9 年前
當你使用 sqlsrv_prepare 將變數綁定到語句時,請務必小心。

考慮以下情況

<?php
$dude
= '';
$time = new DateTime();
$sql = "INSERT INTO my_table (person, timein) VALUES (?, ?)";
$stmt = sqlsrv_prepare($conn, $sql, array(&$dude, &$time));

...
// 許多行程式碼之後

foreach ($times as &$time) {
// 執行一些操作
}

// 稍後...
$time = $times['start'];
if(
sqlsrv_execute( $stmt ) === false ) {
die(
print_r( sqlsrv_errors(), true));
}
?>

我做了類似的事情。我一開始準備了一個語句,在中間再次使用該變數,然後在執行查詢之前設定我想要的值。

問題是,我將該變數用作迭代器,而不是簡單的純量。這導致 PHP 使用了記憶體中的不同位置,而先前綁定的位置則無效。因此,SQL 只插入了一個預設的日期/時間。

更糟糕的是,因為 SQL 只是插入了一個預設值,它沒有拋出任何錯誤,而且在嘗試除錯時,我做了類似這樣的事情

<?php
var_dump
($time);
sqlsrv_execute($stmt);
$q = "SELECT * FROM my_table WHERE id=@@IDENTITY";
$r = sqlsrv_query($conn, $q);
$row = sqlsrv_fetch_array($r); $id = $row[0];
var_dump($row['time']);
?>

看起來好像你正在將正確的資料傳送到 SQL,然後看到它吐回完全不同的東西,這絕對令人抓狂。

因此,如果 SQL 似乎正在使用預備語句插入垃圾資料,請確保您沒有在其他任何地方使用這些變數。
-2
matt at bigbadweb dot co dot uk
10 年前
如何正式指定參數並取得輸出的範例。
<?php

// 設定連線
$serverName = "serverName\sqlexpress";
$connectionInfo = array( "Database"=>"dbName", "UID"=>"username", "PWD"=>"password");
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if(
$conn === false) {
die(
print_r( sqlsrv_errors(), true));
}

// 指定參數 - 必須是可以透過參照傳遞的變數!
$myparams['Item_ID'] = intval(-2);
$myparams['Item_Name'] = "Foo";

// 設定程序參數陣列 - 請務必透過參照傳遞參數
$procedure_params = array(
array(&
$myparams['Item_ID'], SQLSRV_PARAM_OUT),
array(&
$myparams['Item_Name'], SQLSRV_PARAM_OUT)
);

// 執行該程序,{call stp_Create_Item (@Item_ID = ?, @Item_Name = ?)} 在我的實驗中似乎會失敗並出現各種錯誤
$sql = "EXEC stp_Create_Item @Item_ID = ?, @Item_Name = ?";

$stmt = sqlsrv_prepare($conn, $sql, $procedure_params);

if( !
$stmt ) {
die(
print_r( sqlsrv_errors(), true));
}

if(
sqlsrv_execute($stmt)){
while(
$res = sqlsrv_next_result($stmt)){
// 請務必逐步執行所有結果集,因為輸出參數可能要到執行此操作後才會設定
}
// 輸出參數現在已設定,
print_r($params);
print_r($myparams);
}else{
die(
print_r( sqlsrv_errors(), true));
}
?>
To Top