Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Oba ovladače mohou příkaz spustit jednou nebo připravit příkaz pro opakované provedení. Používejte parametry pro hodnoty zadané uživateli, i když dotaz spustíte pouze jednou.
Vyberte API pro provádění odděleně od způsobu, jakým načítáte výsledky. Příprava dotazu nenačítá jeho řádky a ukládání výsledků do bufferu neudělá dotaz parametrizovaným. Následující příklady připraví dotaz pouze pro čtení jednou, provedou ho dvakrát s různými hodnotami a spotřebují každý výsledek před dalším vykonáním.
| Styl provedení | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Spusť dotaz jednou, bez parametrů | sqlsrv_query | PDO::query na výsledky nebo PDO::exec pro počty ovlivněných řádků |
| Spusť dotaz jednou s parametry | sqlsrv_query($conn, $sql, $params) |
PDO::prepare() a pak PDOStatement::execute() |
| Připravte jednou, spouštějte opakovaně s různými parametry | sqlsrv_prepare + sqlsrv_execute | PDO::prepare + PDOStatement::execute |
sqlsrv_query() připraví a vykoná v jednom volání a vrátí prostředek statementu.
sqlsrv_prepare() vrací příkazový zdroj bez jeho vykonání; zavolejte sqlsrv_execute() při každém provedení. PDO vykoná query() a vrátí PDOStatement, zatímco exec() místo výsledného objektu vrací počet ovlivněných řádků. Úspěšný exec() může vrátit 0, takže porovnejte návratovou hodnotu při selhání s === false, nikoli if (!$count).
PDO::query() nepřijímá pole hodnot parametrů. Volitelné argumenty konfigurují načítání. Pro parametrizované PDO_SQLSRV dotazy použijte prepare() a execute().
Příprava jednou vám umožní znovu použít handle příkazu s různými hodnotami. To není záruka, že server nikdy nepřekompiluje svůj plán vykonání. PDO_SQLSRV používá připravené provádění ve výchozím nastavení, včetně pro PDO::query(); jeho atribut přímého dotazu řídí tuto samostatnou volbu.
Připravte se jednou a spouštějte opakovaně
Jedná se o samostatné, kompletní programy příkazového řádku. Nainstalujte a načtěte vybrané rozšíření a nastavte SQL_SERVER, SQL_DATABASE, , SQL_USERa SQL_PASSWORD v procesním prostředí PHP. Použijte testovací databázi SQL Server a serverový certifikát, kterému klientský systém důvěřuje. Pro nastavení prostředí a bezheslové alternativy viz Připojení k serveru.
Uložte skutečné jméno databáze, uživatelské jméno a heslo do proměnných prostředí. Oba programy provedou escapování těchto hodnot jednou tím, že zdvojnásobí zavírací závorky a každou hodnotu uzavřou do závorek, jak vyžaduje PHP ovladač při zpracování připojení ve stylu ODBC. Escapování hodnot připojení je oddělené od vázání parametrů dotazu.
Programy vykonávají dotaz Transact-SQL (T-SQL) nad dvěma vloženými řádky, aniž by vytvářely tabulku nebo měnily data. Uložte každý program do samostatného .php souboru a spusťte ho pomocí php <file>. Není potřeba žádná vzorová databáze.
SQLSRV
Předejte $productId odkazem s &$productId. Každý sqlsrv_execute() pak použije svou aktuální hodnotu.
SQLSRV_FETCH_ASSOC vrací pole klíčované podle názvu sloupce. Výsledek znamená, že už nejsou žádné řádky; false znamená null chybu.
<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name before running this example.");
}
$config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$conn = sqlsrv_connect($config['SQL_SERVER'], [
'Database' => $config['SQL_DATABASE'],
'UID' => $config['SQL_USER'],
'PWD' => $config['SQL_PASSWORD'],
'Encrypt' => true,
'TrustServerCertificate' => false,
'LoginTimeout' => 30,
'CharacterSet' => 'UTF-8',
]);
if ($conn === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$sql = "SELECT Name FROM (VALUES (1, 'Bike'), (2, 'Helmet')) AS Product(ProductId, Name) WHERE ProductId = ?";
$productId = 1;
$stmt = null;
try {
$stmt = sqlsrv_prepare($conn, $sql, [&$productId], ['QueryTimeout' => 30]);
if ($stmt === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
foreach ([1 => 'Bike', 2 => 'Helmet'] as $productId => $expected) {
if (!sqlsrv_execute($stmt)) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$names = [];
while (($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) !== null) {
if ($row === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$names[] = $row['Name'];
}
if ($names !== [$expected]) {
throw new RuntimeException('Expected exactly one matching product.');
}
echo $names[0], PHP_EOL;
}
} finally {
if (is_resource($stmt)) {
sqlsrv_free_stmt($stmt);
}
sqlsrv_close($conn);
}
PDO_SQLSRV
Jednorázově svažte $productId s bindParam(). Každý z nich execute() čte svou aktuální hodnotu.
PDO::PARAM_INT specifikuje typ vazby PHP/PDO parametru; neovlivňuje PHP typ sloupců načtených z výsledku. Nastavte režim výjimky tak, aby chyba v databázi přerušila vykonání, místo aby byla mylně považována za prázdný výsledek.
<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name before running this example.");
}
$config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$server = $config['SQL_SERVER'];
$database = $config['SQL_DATABASE'];
$pdo = new PDO(
"sqlsrv:Server=$server;Database=$database;Encrypt=true;"
. "TrustServerCertificate=false;LoginTimeout=30",
$config['SQL_USER'],
$config['SQL_PASSWORD'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8,
]
);
$sql = "SELECT Name FROM (VALUES (1, 'Bike'), (2, 'Helmet')) AS Product(ProductId, Name) WHERE ProductId = ?";
$stmt = null;
try {
$stmt = $pdo->prepare($sql, [PDO::SQLSRV_ATTR_QUERY_TIMEOUT => 30]);
$productId = 1;
$stmt->bindParam(1, $productId, PDO::PARAM_INT);
foreach ([1 => 'Bike', 2 => 'Helmet'] as $productId => $expected) {
$stmt->execute();
$names = $stmt->fetchAll(PDO::FETCH_COLUMN);
if ($names !== [$expected]) {
throw new RuntimeException('Expected exactly one matching product.');
}
echo $names[0], PHP_EOL;
$stmt->closeCursor();
}
} finally {
$stmt = null;
$pdo = null;
}
Každý příklad vypíše:
Bike
Helmet
Hodnoty v poli předaném do PDO execute() jsou považovány za PDO::PARAM_STR. Když SQL vyžaduje celočíselný parametr, například parametrizovaný TOP počet, volejte bindValue() s PDO::PARAM_INT a poté volejte execute() bez pole.
Svazujte hodnoty bez změny dotazu
Parametr označuje hodnotu, nikoli název tabulky, název sloupce, klíčové slovo nebo směr třídění. Nedávejte kolem ? uvozovky. Pro dynamický identifikátor nebo ASC/DESC vyberte z aplikačně řízeného seznamu povolených položek místo spojování nedůvěryhodného textu. Pro IN seznam uveďte jeden marker na každou hodnotu.
| Requirement | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Navázat hodnoty pro jedno provedení | Předejte pole parametrů do sqlsrv_query(). |
Předejte pole do execute() po prepare(), nebo nejprve přiřaďte hodnoty. |
| Znovu použít aktuální hodnotu proměnné | Zahrň &$variable do pole dodaného do sqlsrv_prepare(). |
Volejte bindParam() s proměnnou, pak execute() bez pole. PHP předává proměnnou podle odkazu; nepřidávejte & na místě volání. |
| Svázejte hodnotu v době vázání | Pro provedení použijte hodnotu v poli parametrů. | Zavolejte bindValue(); pozdější změny původní proměnné tuto navázanou hodnotu nezmění. |
| Zadejte celočíselný vstup | Použijte deskriptor parametru s SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, a SQLSRV_SQLTYPE_INT když je potřeba explicitní typ. |
Propojit s PDO::PARAM_INT. Pozicionistické bindParam() a indexové začínají bindValue() na , nikoli 0na 1. |
Odeslat SQL NULL |
Svažte PHP null s explicitním SQL typem, pokud to operace vyžaduje. |
Svázat pomocí PDO::PARAM_NULL. |
| Přijmout výstupní parametry | Použijte odkazovanou proměnnou s SQLSRV_PARAM_OUT nebo SQLSRV_PARAM_INOUT. |
Použijte bindParam() s PDO::PARAM_INPUT_OUTPUT požadovaným typem a délkou. |
Udržujte odkazované proměnné aktivní při provádění připraveného příkazu. Program SQLSRV mění boundovanou proměnnou namísto toho, aby nahradil pole parametrů. Program PDO záměrně volá execute() bez pole po navázání parametrů; tento vzor nemíchejte s prováděním založeným na poli.
Výstupní hodnoty z uložených procedur vyžadují vlastní zpracování, včetně zpracování výsledků procedury. Neodvozujte chování výstupních parametrů z těchto pouze vstupních příkladů. Pro více informací viz Použití směrových parametrů.
Konfigurovat chování při provádění a načítání
| Setting | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Časový limit vykonání |
QueryTimeout v poli voleb příkazu. |
PDO::SQLSRV_ATTR_QUERY_TIMEOUT u připojení nebo příkazu. |
| Pojmenované klíče výsledku |
SQLSRV_FETCH_ASSOC předáno do sqlsrv_fetch_array(). |
PDO::FETCH_ASSOC lze předat metodě fetch nebo nastavit jako výchozí režim načítání připojení. |
| Výsledky pouze pro postup vpřed | Výchozí kurzor; načítat v pořadí. | Výchozí kurzor; načítat v pořadí. |
| Výsledky ukládané do vyrovnávací paměti klienta |
Scrollable => SQLSRV_CURSOR_CLIENT_BUFFERED. |
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL s PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED. |
| Přímé versus připravené spuštění | Žádný atribut pro přímý dotaz PDO. Vyberte kombinované sqlsrv_query() volání nebo explicitní dvojici prepare/execute. |
PDO::SQLSRV_ATTR_DIRECT_QUERY určuje přímé spuštění namísto výchozího připraveného spuštění ovladače. |
| Emulace parametrů | Žádná emulace PDO. |
PDO::ATTR_EMULATE_PREPARES je oddělený od atributu direct query. Nepoužívej ho jako náhradu za svázání správných typů. |
Příklady vracejí omezené výsledky.
fetchAll() načte každý řádek do paměti PHP; pro rozsáhlou sadu výsledků použijte cyklus pro načítání řádků. Dotaz, který nevrátí žádné výsledky, není chyba při provádění. SQLSRV hlásí konec výsledku jako null z sqlsrv_fetch_array(); PDO hlásí konec výsledku jako false z fetch(). SQL NULL v načteném řádku zůstává PHP null.
Nepoužívejte počet řádků SELECT jako jediné ověření úspěchu. kurzory pouze pro posun vpřed neposkytují stejné možnosti zjištění počtu řádků jako bufferované nebo posouvatelné kurzory. Načtěte a spočítejte požadované řádky nebo použijte samostatný dotaz COUNT. Pro možnosti a omezení specifické pro kurzor viz Specifikujte typ kurzoru a vyberte řádky.
Řešení selhání a výsledky dokončení
Zkontrolujte operace SQLSRV pro přípravu, provedení a načítání samostatně. Úspěšná příprava příkazu nedokazuje, že jeho provedení bude úspěšné: server může při provádění odmítnout hodnoty parametrů, oprávnění nebo samotný příkaz. Zachyťte sqlsrv_errors() okamžitě, jakmile operace vrátí false. SQLSRV standardně považuje mnoho varování za chyby, proto zkontrolujte úplný seznam.
V PDO jsou v režimu výjimek při selhání připojení a databázových chybách vyvolány výjimky PDOException. Zkontrolujte jeho SQLSTATE a informace o chybách ovladače v chráněné diagnostice aplikace; nevracejte text výjimky ani přihlašovací údaje v odpovědi HTTP.
prepare() to, že operace uspěla, není důkazem, že příkaz už byl spuštěn.
| Symptom | Action |
|---|---|
| Každé provedení používá první hodnotu | Pro SQLSRV svažte proměnnou odkazem. Pro PDO použijte bindParam() pro proměnnou, která se mění, nebo volejte bindValue() pro každou novou hodnotu. |
Číselný parametr, například TOP počet, je zamítnut. |
Výslovně zadejte požadovaný celočíselný typ. PDO execute([$value]) používá řetězcové parametry, i v případě, že hodnota v PHP je celé číslo. |
| Druhý příkaz oznamuje výsledky čekající na zpracování. | Zpracujte výsledky nebo je uvolněte před opětovným použitím připojení. V případě PDO použijte closeCursor(), když nepotřebujete zbývající výsledek. |
| Očekávané výstupní parametry se nezměnily | Dokončete všechny výsledky procedur a ověřte směr parametru, datový typ v PHP a délku výstupního bufferu. |
| Využití paměti roste s velikostí výsledku | Nahraďte fetchAll() nebo zbytečné ukládání do vyrovnávací paměti na straně klienta sekvenčním načítáním. |
Příklady uvolňují příkazy a uzavírají připojení v finally. Nezačínají transakci. Použijte explicitní transakci, když je nutné, aby se více zápisů buď potvrdilo společně, nebo aby se všechny vrátily zpět. Opětovné použití připraveného příkazu neseskupí zápisy do jedné transakce.
Rozdíly mezi cílovým stavem a implementací
Rozhraní prepare/execute API a pravidla pro reference v PHP spadají pod rozšíření a PHP/PDO. Cílová platforma SQL rozhoduje, které příkazy a typy T-SQL jsou podporovány, a ODBC provádí základní komunikaci. Jednorázová příprava může snížit opakovanou práci, ale nezaručuje konkrétní plán provádění na serveru ani zrychlení.
Vzory vazby vstupů se vztahují na SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics, SQL databázi v Microsoft Fabric a Warehouse v Microsoft Fabric. Tyto programy používají ověřování SQL pro připojení k serveru SQL Server. Pro onboarding v Azure upřednostněte autentizaci Microsoft Entra. Oba produkty Fabric to vyžadují a Warehouse také vyžaduje vypnutí více aktivních sad výsledků (MARS). Před opětovným použitím kódu SQL Server zkontrolujte podporu vybraného cíle pro změny schémat, transakce a uložené procedury. Pro rozdíly mezi koncovými body a ověřováním viz připojení Azure a Fabric.