Zum Inhalt springen

Lesen aus der Datenbank

In folgenden PHP-Beispielen wird eine Datenbank mit den Tabellen users und projects verwendet.

So kann mein ein einfaches SELECT von PHP aus absetzten. Als Antwort erhält man von der Datenbank eine ganze Tabelle an Werten: mehrere Zeilen (hier: Personen) mit mehreren Spalten (hier: die verscheidenen Eigenschaften der Person)

$sth =$dbh->query(
"SELECT * FROM users WHERE profile_visible ORDER BY surname LIMIT 500"
);
$users = $sth->fetchAll();

Die SQL-Anfrage wird hier als String an die query()-Methode des Datenbankhandler übergeben.

Der Rückgabewert von query ist ein Statement-Handle $sth (ähnlich dem Datenbank-Handle).

Erst beim Aufruf von fetchAll() werden die Daten von der Datenbank geladen.

$sth =$dbh->query(
"SELECT * FROM users WHERE profile_visible ORDER BY surname LIMIT 500"
);
$users = $sth->fetchAll();
echo "Der erste User heisst $users[0][2]"

$users enthält nun ein Array aller Datensätze, jeder Datensatz ist wieder ein Array.

Mit dem Befehl print_r kann man die gesamte Datenstruktur auf einmal ausgeben - das ist nur fürs debuggen geeignet, nicht für Enduser:

<pre><?php print_r($users) ?></pre>

Jeder Datensatz enthält also die Werte zweimal: einmal unter einem numerischen index 0,1,2… und einmal unter dem Namen der Datenbank-Spalte.

Mit der foreach Schleife kann man ein Array abarbeiten. Nach dem Schlüsselwort as gibt man die Schleifenvariable an, die bei jedem Durchlauf auf eine anderen Eintrag des Arrays gesetzt wird.

foreach( $users as $user ) {
// gib Vorname und Nachname aus
echo "<h2>$user[1] $user[2]</h2>";
}

Falls man den Index auch anzeigen will, kann man die ausführlichere Version der foreach Schleife verwenden:

Foreach-Schleife mit index
foreach($personen as $i => $person) {
echo "<li>Person Nr. $i) $person->firstname $person->surname</li>\n";
}

Achtung: $i ist hier der Index im Array das fetchAll() erzeugt hat, es ist nicht der Primary Key aus der Datenbank! Den würde man mit $person->id erhalten!

Bei der “Übersetzung” von Datensätzen zu PHP Datenstrukturen gibt es mehrere Möglichkeiten. Wir können direkt bei fetchAll eine Option angeben.

$sth =$dbh->query(
"SELECT * FROM users WHERE profile_visible ORDER BY lastname LIMIT 500"
);
$users = $sth->fetchAll(PDO::FETCH_NUM);
echo "Der erste User heisst $users[0][2]"

Mit der Option PDO::FETCH_ASSOC erhalten wir die Datensätze als Array, aber der Index ist kein Integer, sondern ein String: jeweils der Name der Tabellen-Spalten entsprechen.

Der Zugriff erfolgt mit eckigen Klammern, wie bei jedem Array: $users[0]['firstname'];

Bei der Verwendung innerhalb eines Strings gibt es aber Probleme: "Der Vorname ist $users[0]['firstname']" funktioniert nicht. Hier braucht man extra geschwungene Klammern rund um die Variable im String.

$sth =$dbh->query(
"SELECT * FROM users WHERE profile_visible ORDER BY lastname LIMIT 500"
);
$users = $sth->fetchAll(PDO::FETCH_ASSOC);
foreach( $users as $user ) {
echo "<h2>{$user['firstname']} {$user['lastname']}</h2>";
}

Mit der Option PDO::FETCH_OBJ erhalten wir die Datensätze als Objekte. Die Objekte gehören zur Klasse stdClass, haben keine Methoden und haben genau die Eigenschaften die den Tabellen-Spalten entsprechen.

$sth =$dbh->query(
"SELECT * FROM users WHERE profile_visible ORDER BY lastname LIMIT 500"
);
$users = $sth->fetchAll(PDO::FETCH_OBJ);
foreach( $users as $user ) {
echo "<h2>$user->firstname $user->lastname</h2>";
}

Wenn man sich für einen Modus entschieden hat, kann man diesen gleich beim Verbindungsaufbau festlegen:

$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

Mit der SQL-Funktion COUNT() können wir die Anzahl der gefundenen Datensätze bestimmen*. Wir wollen also nur einen einzigen Wert aus der Datenbank laden.

Trotzdem brauchen wir mehrere Schritte:

$sth = $dbh->query("SELECT COUNT(*) AS anzahl FROM users WHERE profile_visible");
$result = $sth->fetchAll(PDO::FETCH_OBJ);
$anz_personen = $result[0]->anzahl;

Hier wurde in SQL mit AS eine neue “Spalte” namens anzahl erzeugt. Diese ist dann in PHP auch unter diesem Namen zugänglich.

Man könnte all diese Befehle direkt aneinander-ketten (englisch: “to chain”):

$anz_personen = $dbh->query("SELECT COUNT(*) AS anzahl FROM users WHERE profile_visible")->fetchAll(PDO::FETCH_OBJ)[0]->anzahl;

Damit spart man sich Variablen, macht aber die Fehlersuche etwas schwieriger.

Das Laden der Datensätze aus der Datenbank braucht Zeit. Wenn es Millionen von Datensätzen sind kann das zum Problem werden. In dieser SQL Abfrage wird damit schon gut umgegangen:

$sth =$dbh->query(
"SELECT * FROM person WHERE profile_visible=1 ORDER BY surname LIMIT 500"
);
$personen = $sth->fetchAll();

Im Beispiel wird LIMIT verwendet: LIMIT anzahl bzw. LIMIT anzahl OFFSET anfangsposition wählt aus der Antwort eine Anzahl von Datensätzen aus, beginnt dabei bei Anfangsposition*.

In der Datenbank sind Personen, deren Profil nicht angezeigt werden soll, mit profile_visible = false gekennzeichnet. Im SQL-Statement wird sicher gestellt, dass nur sichtbare Profil angezeigt werden.

Wie kann man zufällige Datensätze auswählen?

Abfrage von 10 zufälligen Datensätzen in einer großen Tabelle
$query =$dbh->query(
"SELECT * FROM users
TABLESAMPLE BERNOULLI (1)
WHERE profile_visible
ORDER BY lastname
LIMIT 10;"
);
$personen = $query->fetchAll(PDO::FETCH_OBJ);

Für sehr kleine Tabellen funktioniert diese Methode besser:

Abfrage von 3 zufälligen Datensätzen in einer kleinen Tabelle
$query =$dbh->query(
"SELECT * FROM users
ORDER BY RANDOM()
LIMIT 3;"
);
$personen = $query->fetchAll(PDO::FETCH_OBJ);

PHP

Postgres

Testen Sie Ihr Wissen — die Antworten werden nur lokal in Ihrem Browser gespeichert.

Was liefert $dbh->query("SELECT * FROM users") zurück?

  • Ein Array aller Datensätze

    Die Daten werden erst beim Aufruf von fetchAll() von der Datenbank geladen.

  • Ein Statement-Handle
  • Die Anzahl der gefundenen Datensätze
  • Den ersten Datensatz als Objekt

Nach $users = $sth->fetchAll(PDO::FETCH_OBJ); — wie greift man auf den Vornamen des ersten Users zu?

  • $users[0]['firstname']

    Eckige Klammern mit String-Index passen zu PDO::FETCH_ASSOC, nicht zu Objekten.

  • $users[0]->firstname
  • $users->firstname[0]
  • $users[0].firstname

    Die Punkt-Notation für Objekte gibt es in JavaScript — in PHP verwendet man ->.

Was bewirkt AS anzahl in SELECT COUNT(*) AS anzahl FROM users?

  • Es erzeugt eine neue „Spalte“ namens anzahl, die in PHP unter diesem Namen zugänglich ist
  • Es benennt die Tabelle users in anzahl um
  • Es sortiert das Ergebnis nach der Spalte anzahl

    Sortiert wird mit ORDER BY.

  • Es beschränkt die Anzahl der Datensätze

    Die Anzahl beschränkt man mit LIMIT.

Warum steht in SELECT * FROM users ORDER BY surname LIMIT 500 die Klausel LIMIT 500?

  • Es werden höchstens 500 Datensätze geladen — wichtig bei Tabellen mit sehr vielen Datensätzen
  • Die Abfrage bricht nach 500 Millisekunden ab
  • Es werden genau 500 Datensätze garantiert

    Sind weniger vorhanden, kommen auch weniger zurück — LIMIT ist eine Obergrenze.

  • Nur die ersten 500 Zeichen jeder Spalte werden geladen

Quiz-Fortschritt

0 / 0 Fragen beantwortet (0%)

0 richtig