Präzise Fragen stellen · Übung
Wenn eine Abfrage keine Zeile findet
Eine Werkzeugsuche kann zwei völlig normale Ergebnisse haben: eine passende Zeile oder überhaupt keine passende Zeile. Python braucht für beide Fälle eine Ergebnisform, damit das Programm reagieren kann, ohne eine leere Suche als kaputte Datenbank zu behandeln.
Das Projekt ruft die Funktion in first_tool.py so auf:
first_tool(connection)
connection enthält bereits einen geöffneten Katalog. Die Funktion sendet diese vollständige, feste Abfrage über diese Verbindung:
cursor = connection.execute(
"""
SELECT asset_tag, name
FROM items
WHERE category = 'tools'
ORDER BY asset_tag ASC
LIMIT 1
"""
)
Der Aufruf von connection.execute(...) übergibt die SQL-Anweisung an SQLite. Der zurückgegebene cursor steht für das Ergebnis dieser Abfrage. Das bedeutet noch nicht, dass Python bereits eine Zeile aus diesem Ergebnis entnommen hat.
Öffne first_tool.py. In der letzten Zeile steht derzeit return None. Ändere nur diese Zeile:
return cursor.fetchone()
Der Aufruf .fetchone() fordert eine Zeile an. Wenn der Katalog Werkzeuge enthält, kommt diese Zeile als Tupel mit den beiden ausgewählten Werten an. Wenn keine Zeile passt, gibt .fetchone() das Python-Objekt None zurück.
Beim sichtbaren Werkzeugergebnis folgen die Tupelpositionen der SELECT-Liste: zuerst das Inventarkennzeichen, dann der Name. Die Funktion baut dieses Tupel nicht selbst. SQLite erzeugt die Zeile, der Cursor hält das Ergebnis bereit, und .fetchone() überträgt eine Ergebniszeile nach Python.
Klicke auf Run. Finde hinter dem bestehenden Abschnitt für search.sql diese beiden Aufrufe:
== first_tool.py ==
first_tool(connection) with tools
('TL-100', 'Cordless drill')
first_tool(connection) without tools
None
Jeder Aufruf erhält eine eigene offene Verbindung. Der erste Katalog enthält Werkzeugzeilen, der zweite absichtlich keine. Die Funktion und ihr wörtlich angegebenes SQL bleiben genau gleich.
Sage vor dem Ausführen den zweiten ausgegebenen Wert voraus. Die Abfrage enthält weiterhin gültiges SQL, die Tabelle existiert noch, und keine Datenbankoperation ist fehlgeschlagen. Der einzige Unterschied ist, dass keine gespeicherte Zeile category = 'tools' hat. None zu sehen bestätigt, dass eine leere Suche Daten liefert, mit denen dein Programm umgehen kann, statt eine Ausnahme, die behoben werden muss.
Python None bedeutet hier, dass die Abfrage null Zeilen erzeugt hat. Es unterscheidet sich von SQL NULL, einem Wert, der innerhalb einer Zeile vorkommen kann. Eine Zeile wie ('TL-100', NULL) wäre weiterhin eine Zeile und käme in Python als Tupel mit None darin an. Diese Übung gibt überhaupt kein Tupel zurück, wenn es kein Werkzeug gibt.
Behalte beim Lesen dieser Unterscheidung den aufrufenden Code im Blick. Code, der first_tool(connection) verwendet, kann mit if result is None prüfen, bevor er versucht, Tupelpositionen zu lesen. Er erhält für jedes mögliche Ergebnis eine vorhersehbare Python-Form.
Submit probiert andere Kennzeichen und Einfügereihenfolgen aus. Behalte die vorgegebene Sortierung und das Limit bei, damit „erstes“ vorhersehbar bleibt, und gib den Wert von .fetchone() zurück, nicht den Cursor oder eine Liste von Zeilen.
Eine leere Antwort ist weiterhin eine gültige Antwort. Deine Funktion gibt dem aufrufenden Code jetzt ein Tupel, wenn ein Werkzeug existiert, und ein eindeutiges None, wenn keines existiert.
Aufgabe
Ändere in first_tool.py die letzte Zeile zu return cursor.fetchone().
Führe das Projekt aus und prüfe beide ausgegebenen Aufrufe: Einer sollte ein Tupel mit zwei Werten zurückgeben, und der Katalog ohne Werkzeuge sollte None zurückgeben.