Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Beide Treiber können eine Anweisung einmal ausführen oder eine Anweisung für wiederholte Ausführung vorbereiten. Verwenden Sie Parameter für von Benutzern bereitgestellte Werte, selbst wenn Sie eine Abfrage nur einmal ausführen.
Wähle die Ausführungs-API getrennt davon aus, wie du die Ergebnisse abrufst. Die Vorbereitung einer Abfrage holt ihre Zeilen nicht, und das Puffern eines Ergebnisses macht eine Abfrage nicht parametrisiert. Die folgenden Beispiele bereiten eine schreibgeschützte Abfrage einmal vor, führen sie zweimal mit unterschiedlichen Werten aus und verbrauchen jedes Ergebnis vor der nächsten Ausführung.
| Ausführungsstil | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Führe eine Abfrage einmalig ohne Parameter aus | sqlsrv_query | PDO::query für Ergebnisse, oder PDO::exec für betroffene Zeilenzählungen |
| Führe eine Abfrage einmalig mit Parametern aus | sqlsrv_query($conn, $sql, $params) |
PDO::prepare() gefolgt von PDOStatement::execute() |
| Einmal vorbereiten, wiederholt mit verschiedenen Parametern ausführen | sqlsrv_prepare + sqlsrv_execute | PDO::prepare + PDOStatement::execute |
sqlsrv_query() bereitet in einem Aufruf vor, führt aus und gibt eine Statement-Ressource zurück.
sqlsrv_prepare() gibt eine Anweisungsressource zurück, ohne sie auszuführen; rufen Sie sqlsrv_execute() für jede Ausführung auf. PDO query() führt aus und gibt PDOStatement zurück, während exec() eine betroffene Zeilenanzahl statt eines Ergebnisobjekts zurückgibt. Ein erfolgreicher exec() kann 0 zurückgeben, also vergleiche eine Fehlschlagsrückgabe mit === false, nicht if (!$count).
PDO::query() akzeptiert kein Array von Parameterwerten. Seine optionalen Argumente konfigurieren das Abrufen. Für parametrisierte PDO_SQLSRV Abfragen verwenden Sie prepare() und execute().
Einmal vorbereiten ermöglicht es dir, einen Statement-Handle mit anderen Werten wiederzuverwenden. Das ist keine Garantie, dass der Server seinen Ausführungsplan niemals neu kompiliert. PDO_SQLSRV verwendet standardmäßig die vorbereitete Ausführung von Anweisungen, einschließlich für PDO::query(); das Attribut „direct-query“ steuert diese separate Auswahl.
Einmal vorbereiten und wiederholt ausführen
Dies sind separate, vollständige Kommandozeilenprogramme. Installiere und lade die ausgewählte Erweiterung und setze SQL_SERVER, SQL_DATABASE, , SQL_USERund SQL_PASSWORD in der PHP-Prozessumgebung. Verwenden Sie eine SQL Server-Testdatenbank und ein vom Client vertrauenswürdiges Serverzertifikat. Für die Umgebungseinrichtung und passwortlose Alternativen siehe Verbinden mit dem Server.
Speichere den tatsächlichen Datenbanknamen, Benutzernamen und Passwort in den Umgebungsvariablen. Beide Programme maskieren diese Werte einmal, indem sie schließende geschweifte Klammern verdoppeln und jeden Wert in geschweifte Klammern einschließen, wie es die ODBC-ähnliche Verbindungshandhabung des PHP-Treibers verlangt. Das Escapen von Verbindungswerten ist getrennt von der Bindung von Abfrageparametern.
Die Programme führen eine Transact-SQL (T-SQL)-Abfrage über zwei Inlinezeilen aus, ohne eine Tabelle zu erstellen oder Daten zu ändern. Speichere jedes Programm in einer eigenen .php Datei und führe es mit php <file>aus. Es ist keine Beispieldatenbank erforderlich.
SQLSRV
Übergeben Sie $productId per Referenz mit &$productId. Jedes sqlsrv_execute() verwendet dann seinen aktuellen Wert.
SQLSRV_FETCH_ASSOC gibt ein Array zurück, das Spaltennamen als Schlüssel verwendet. Ein Ergebnis bedeutet, dass es keine Zeilen mehr gibt; false zeigt null einen Fehler an.
<?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
Binde $productId einmal mit bindParam(). Jeder execute() liest seinen aktuellen Wert aus.
PDO::PARAM_INT spezifiziert den PHP/PDO-Bindungstyp des Parameters; er kontrolliert nicht den PHP-Typ der aus dem Ergebnis abgerufenen Spalten. Stellen Sie den Ausnahmemodus so ein, dass ein Datenbankfehler die Ausführung unterbricht, anstatt für ein leeres Ergebnis gehalten zu werden.
<?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;
}
Jedes Beispiel druckt:
Bike
Helmet
Werte in einem Array, das an PDO's execute() übergeben wird, werden als PDO::PARAM_STR behandelt. Wenn SQL einen ganzzahligen Parameter verlangt, wie zum Beispiel eine parametrisierte TOP Zählung, rufen Sie bindValue() mit PDO::PARAM_INT auf und rufen Sie dann execute() ohne Array auf.
Werte binden, ohne die Abfrage zu ändern
Ein Parametermarker stellt einen Wert dar, nicht einen Tabellennamen, Spaltennamen, Schlüsselwort oder Sortierrichtung. Setze keine Anführungszeichen um ?. Für eine dynamische Kennung oder ASC/DESC, wählen Sie aus einer von der Anwendung gesteuerten Erlaubnisliste aus, anstatt nicht vertrauenswürdigen Text zu verketten. Für eine IN Liste gib pro Wert einen Marker an.
| Requirement | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Binde Werte für eine Ausführung | Übergebe das Parameterarray an sqlsrv_query(). |
Übergebe ein Array an execute() nach prepare(), oder binde zuerst Werte. |
| Wiederverwenden Sie den aktuellen Wert einer Variablen | Fügen Sie in das bereitgestellte sqlsrv_prepare()Array ein.&$variable |
Ruf bindParam() mit der Variablen, dann execute() ohne ein Array. PHP übergibt die Variable als Referenz; nicht am Aufrufstandort hinzufügen & . |
| Binde einen Wert zum Zeitpunkt der Bindung | Verwenden Sie einen Wert im Parameterarray für die Ausführung. | Rufen bindValue()Sie ; spätere Änderungen an der ursprünglichen Variable ändern diesen Bound-Wert nicht. |
| Spezifizieren Sie eine ganzzahlige Eingabe | Verwenden Sie einen Parameterdeskriptor mit SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, und SQLSRV_SQLTYPE_INT wenn ein expliziter Typ benötigt wird. |
Binde mit PDO::PARAM_INT. Positions- bindParam() und bindValue() Indizes beginnen bei , nicht 0.1 |
SQL senden NULL |
Binde PHP null, wenn es die Operation benötigt, mit einem expliziten SQL-Typ. |
Binde mit PDO::PARAM_NULL. |
| Empfangsausgabeparameter | Verwenden Sie eine referenzierte Variable mit SQLSRV_PARAM_OUT oder SQLSRV_PARAM_INOUT. |
Verwenden Sie bindParam() mit PDO::PARAM_INPUT_OUTPUT und der erforderlichen Art und Länge. |
Halten Sie die referenzierten Variablen aktiv, während Sie die vorbereitete Anweisung ausführen. Das SQLSRV-Programm ändert die gebundene Variable, anstatt das Parameterarray zu ersetzen. Das PDO-Programm ruft execute() nach der Bindung bewusst ohne Array auf; mischen Sie dieses Muster nicht mit arraybasierter Ausführung.
Ausgabewerte aus gespeicherten Prozeduren erfordern eine eigene Handhabung, einschließlich des Abschlusses der Prozedurergebnisse. Schließen Sie das Verhalten der Ausgabeparameter nicht aus diesen reinen Eingabebeispielen ab. Weitere Informationen finden Sie unter Verwendung von Richtungsparametern.
Ausführungs- und Fetch-Verhalten konfigurieren
| Setting | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Ausführungszeit |
QueryTimeout im Options-Array der Anweisung. |
PDO::SQLSRV_ATTR_QUERY_TIMEOUT auf der Verbindung oder Aussage. |
| Benannte Ergebnisschlüssel |
SQLSRV_FETCH_ASSOC übergab an sqlsrv_fetch_array(). |
PDO::FETCH_ASSOC an eine Fetch-Methode übergeben oder als Standard-Fetch-Modus der Verbindung eingestellt. |
| Vorwärts-only-Ergebnisse | Standard-Cursor; der Reihe nach abrufen. | Standard-Cursor; holen in der richtigen Reihenfolge. |
| Client-gepufferte Ergebnisse |
Scrollable => SQLSRV_CURSOR_CLIENT_BUFFERED. |
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL durch PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED. |
| Direkte Ausführung im Vergleich zur vorbereiteten Ausführung | Kein Attribut für direkte PDO-Abfragen. Wähle den kombinierten sqlsrv_query() Aufruf oder das explizite Paar aus prepare und execute. |
PDO::SQLSRV_ATTR_DIRECT_QUERY wählt die direkte Ausführung anstelle der standardmäßigen vorbereiteten Ausführung des Treibers aus. |
| Parameteremulation | Kein PDO-Emulationsattribut. |
PDO::ATTR_EMULATE_PREPARES ist vom Attribut „Direktabfrage“ getrennt. Verwende es nicht als Ersatz für das Binden der richtigen Typen. |
Die Beispiele liefern wenige Ergebnisse.
fetchAll() lädt jede Zeile in den PHP-Speicher; benutze eine Fetch-Schleife für ein großes Ergebnis. Eine Abfrage, die keine Übereinstimmungen liefert, ist kein Ausführungsfehler. SQLSRV meldet das Ende des Resultsets als null von sqlsrv_fetch_array(); PDO meldet es als false von fetch(). Ein SQL NULL innerhalb einer abgerufenen Zeile bleibt PHP null.
Verwende keine Zeilenzählung SELECT als einzigen Erfolgscheck. Nur-vorwärts-Cursor bieten nicht die gleichen Zeilenzählfunktionen wie gepufferte oder scrollbare Cursor. Holen und zählen Sie die benötigten Zeilen oder verwenden Sie eine separate COUNT Abfrage. Für cursorspezifische Optionen und Einschränkungen siehe Einen Cursortyp angeben und Zeilen auswählen.
Fehler und Abschlussergebnisse behandeln
Überprüfen Sie SQLSRV-Vorbereitungs-, Ausführungs- und Abrufvorgänge getrennt. Ein erfolgreiches Vorbereiten beweist nicht, dass die Ausführung erfolgreich sein wird: Der Server kann Parameterwerte, Berechtigungen oder die Anweisung zur Ausführungszeit ablehnen. Erfassen Sie sqlsrv_errors() sofort, wenn eine Operation false zurückgibt. SQLSRV behandelt viele Warnungen standardmäßig als Fehler, daher inspizieren Sie die vollständige Sammlung.
Bei PDO werfen Verbindungsausfälle und Datenbankfehler im Ausnahmemodus PDOException. Überprüfen Sie dessen SQLSTATE- und Treiberfehlerinformationen in geschützten Anwendungsdiagnostiken; geben Sie keinen Ausnahmetext oder keine Zugangsdaten in einer HTTP-Antwort zurück.
prepare() Das erfolgreiche Ausführen ist kein Beweis dafür, dass die Anweisung bereits ausgeführt wurde.
| Symptom | Action |
|---|---|
| Jede Ausführung verwendet den ersten Wert | Für SQLSRV, binde eine Variable als Referenz. Verwenden Sie für PDO bindParam() für eine sich ändernde Variable oder rufen Sie bindValue() für jeden neuen Wert auf. |
Ein numerischer Parameter wird zurückgewiesen, wie zum Beispiel eine TOP Zählung |
Binde explizit den erforderlichen Ganzzahltyp. PDO execute([$value]) verwendet String-Parameter, selbst wenn der PHP-Wert eine ganze Zahl ist. |
| Ein zweiter Befehl zeigt noch ausstehende Ergebnisse an | Konsumiere die Ergebnisse oder gib sie frei, bevor du die Verbindung wiederverwendest. Für PDO solltest du verwenden closeCursor() , wenn du das restliche Ergebnis nicht brauchst. |
| Die erwarteten Ausgangsparameter haben sich nicht geändert | Schließen Sie alle Prozedurergebnisse ab und überprüfen Sie die Parameterrichtung, den PHP-Typ und die Ausgabepufferlänge. |
| Der Speicherverbrauch wächst mit der Ergebnisgröße | Ersetzen Sie fetchAll() oder unnötiges Client-Puffern durch sequentielles Abrufen. |
Die Beispiele geben ihre Anweisungen frei und schließen ihre Verbindungen in finally. Sie beginnen keine Transaktion. Verwenden Sie eine explizite Transaktion , wenn mehrere Schreibvorgänge entweder gemeinsam committen müssen oder alle zurückgerollt werden müssen. Die Wiederverwendung eines Prepared Statement gruppiert die Schreibvorgänge nicht zu einer Transaktion.
Unterschiede zwischen Zielplattform und Implementierung
Die Prepare/Execute-APIs und PHP-Referenzregeln gehören zu den Erweiterungen und PHP/PDO. Das SQL-Ziel entscheidet, welche T-SQL-Anweisungen und -Typen unterstützt werden, und ODBC führt die zugrunde liegende Kommunikation durch. Eine einmalige Vorbereitung kann wiederholte Arbeit reduzieren, garantiert aber keinen bestimmten Serverausführungsplan oder eine Beschleunigung.
Die Eingabebindungsmuster gelten für SQL Server, Azure SQL-Datenbank, Azure SQL Managed Instance, Azure Synapse Analytics, SQL Database in Microsoft Fabric und Warehouse in Microsoft Fabric. Diese Programme verwenden SQL-Authentifizierung bei SQL Server. Für das Azure-Onboarding bevorzugen Sie die Microsoft Entra-Authentifizierung. Beide Fabric-Produkte erfordern dies, und Warehouse erfordert außerdem das Deaktivieren von Multiple Active Result Sets (MARS). Überprüfen Sie die Unterstützung des ausgewählten Ziels für Schemaänderungen, Transaktionen und gespeicherte Prozeduren, bevor Sie SQL Server-Code wiederverwenden. Für Unterschiede bei Endpunkten und Authentifizierung siehe Azure- und Fabric-Verbindungen.