INSERT: Zeilen einfügen
Kurz gesagt: INSERT INTO … VALUES fügt eine Zeile ein, INSERT … SELECT fügt Zeilen aus einer Abfrage ein, und die Regeln der Tabelle (UNIQUE, NOT NULL, CHECK, Fremdschlüssel) lehnen falsche Zeilen ab.
Problem
Ein neuer Kunde
Bisher hast du nur aus der Datenbank gelesen. Aber jeden Tag kommt Neues hinein. Heute hat sich Vesela Raykova aus Pleven auf der Website angemeldet.
Die Website muss eine neue Zeile in customers schreiben. Niemand öffnet die Tabelle von Hand: Das Programm schickt der Datenbank eine Abfrage.
Die Idee
INSERT INTO
INSERT INTO sagt, in welche Tabelle und in welche Spalten, und VALUES gibt die Werte in derselben Reihenfolge:
Die Spalte id steht nicht in der Liste. Sie ist ein Primärschlüssel der Art INTEGER PRIMARY KEY, deshalb gibt SQLite ihr selbst eine Nummer, die um eins größer ist als die größte: 21. Eine Spalte, die nicht in der Liste steht, bekommt ihren Standardwert (bei stock im Shop ist das 0), und wenn es keinen gibt, NULL.
Ein Feld kann mehrere Anweisungen enthalten. Sie laufen nacheinander, und das SELECT am Ende zeigt, was passiert ist.
Jedes Feld hat seine eigene Datenbank und behält sie zwischen den Läufen. Führ die Abfrage noch einmal aus: Beim zweiten Mal lehnt die Datenbank ab, denn Vesela ist mit dieser E-Mail-Adresse schon drin. Der Knopf „Neue Datenbank“ setzt die Datenbank auf den Stand vom Anfang zurück.
Sieh es dir an
Ohne die Liste der Spalten
Die Liste der Spalten kann man weglassen. Dann müssen die Werte alle Spalten abdecken, in der Reihenfolge, die sie in der Tabelle haben:
Lass einen weg, und die Datenbank lehnt ab:
Hier fehlt id. Ohne Liste kann die Datenbank nicht erkennen, welcher Wert für welche Spalte ist. Führ die Spalten also immer auf. So siehst du, was wohin gehört, und die Abfrage geht nicht kaputt, wenn die Tabelle eine neue Spalte bekommt.
Probier es aus
Ein neues Produkt
Der Shop verkauft jetzt Ayran. Füge das Produkt „Ayran“ in Kategorie 4 (Milchprodukte) ein, für 1,30 €, mit 30 auf Lager, heute hinzugefügt (2026-10-25).
Lösung
INSERT INTO products (name, category_id, price, stock, added_at)
VALUES ('Ayran', 4, 1.3, 30, '2026-10-25');INSERT INTO products (name, category_id, price, stock, added_at) VALUES ('Ayran', 4, 1.3, 30, '2026-10-25'). Seine Nummer ist 26, und die Datenbank vergibt sie selbst.
Die Idee
RETURNING
Yavor Penev gibt seine erste Bestellung auf. Die Website speichert die Bestellung und muss danach die Produkte darin speichern. Dafür braucht sie die Nummer der neuen Bestellung, und die vergibt die Datenbank.
RETURNING am Ende eines INSERT gibt Spalten der Zeile zurück, die gerade gespeichert wurde:
Die Bestellung hat die Nummer 61. Ohne RETURNING bräuchtest du eine zweite Abfrage, um es zu erfahren. RETURNING nimmt beliebige Spalten: RETURNING id, ordered_at oder RETURNING *.
Genauer, für Neugierige
RETURNING gibt es in SQLite (seit Version 3.35) und in PostgreSQL. In SQL Server schreibt man dasselbe mit OUTPUT. MySQL hat es nicht: Dort liest man die Nummer nach dem Einfügen mit LAST_INSERT_ID(). SQLite hat eine ähnliche Funktion, last_insert_rowid().
Die Idee
Viele Zeilen auf einmal
In Yavors Bestellung sind Kaffee und zwei Packungen Frischmilch. Mehrere Zeilen gehen mit einem INSERT hinein: Nach VALUES kommen mehrere Klammern, durch Kommas getrennt. In dieser Datenbank gibt es die Bestellung 61 schon:
Die Zeilen können auch aus einer Abfrage kommen. Maria klickt bei ihrer letzten Bestellung (60) auf „Nochmal bestellen“. Die neue Bestellung ist 61, und die Produkte kommen aus einem SELECT statt aus VALUES:
Das ist INSERT … SELECT: Was das SELECT liefert, wird gespeichert. Die Spalten des SELECT müssen zur Liste nach INSERT INTO passen. Der Preis kommt aus products, nicht aus der alten Bestellung, denn er kann sich seitdem geändert haben.
Sieh es dir an
Die Datenbank sagt nein
Die Tabellen des Shops haben Regeln. Verletzt du eine, lehnt die Datenbank die Zeile ab und sagt, welche Regel gebrochen wurde.
Die E-Mail-Adresse eines Kunden muss eindeutig sein (UNIQUE):
Der Name darf nicht fehlen (NOT NULL):
Der Preis darf nicht negativ sein (CHECK):
Eine Bestellung muss zu einem Kunden gehören, den es gibt. customer_id ist ein Fremdschlüssel auf customers, und einen Kunden 99 gibt es nicht:
Jedes Mal wird die Zeile nicht gespeichert, und in der Datenbank ändert sich nichts. Das ist gut so: Ein Fehler im Programm kann die Datenbank nicht mit Bestellungen füllen, die niemandem gehören.
Diese Regeln werden beim Anlegen in die Tabelle selbst geschrieben. Im nächsten Modul schreibst du sie selbst.
Probier es aus
Eine Bewertung ohne Text
Simona Yordanova (Kunde 17) gibt der Frischmilch (Produkt 5) heute, am 2026-10-25, 5 Sterne, ohne einen Text zu schreiben. Speichere die Bewertung.
Lösung
INSERT INTO reviews (product_id, customer_id, rating, created_at)
VALUES (5, 17, 5, '2026-10-25');INSERT INTO reviews (product_id, customer_id, rating, created_at) VALUES (5, 17, 5, '2026-10-25'). Die Spalte body steht nicht in der Liste, bleibt also NULL. Sie darf leer sein, rating aber nicht: Probier es ohne.
Übung
Zwei Aufgaben
1. Der Shop baut seine Abteilung „Haushalt“ (Kategorie 2) aus. Füge mit einer Abfrage zwei Unterkategorien hinzu: „Garten“ und „Badezimmer“.
Die zwei neuen Kategorien in „Haushalt“:
Lösung
INSERT INTO categories (name, parent_id)
VALUES ('Garten', 2),
('Badezimmer', 2);INSERT INTO categories (name, parent_id) VALUES ('Garten', 2), ('Badezimmer', 2). parent_id ist 2, weil sie zu „Haushalt“ gehören. Ihre Nummern sind 9 und 10.
2. Ognyan Slavov aus Varna meldet sich heute mit der E-Mail-Adresse ognyan.s@example.com an. Die Website will ihm gleich sein Profil zeigen, mit der Nummer, die die Datenbank ihm gegeben hat. Speichere ihn und gib mit derselben Abfrage die ganze neue Zeile zurück.
Der neue Kunde, die ganze Zeile:
Lösung
INSERT INTO customers (name, email, city, joined_at)
VALUES ('Ognyan Slavov', 'ognyan.s@example.com', 'Varna', '2026-10-25')
RETURNING *;INSERT INTO customers (name, email, city, joined_at) VALUES ('Ognyan Slavov', 'ognyan.s@example.com', 'Varna', '2026-10-25') RETURNING *. Er ist Kunde 21.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: WHERE: Zeilen filtern · NULL: kein Wert · Primärschlüssel und Fremdschlüssel · JOIN: zwei Tabellen in einer Abfrage
- Geht weiter in: UPDATE: Werte ändern · DELETE: Zeilen löschen · Upsert: einfügen oder ändern · Die Datenbank: von CREATE bis DROP
- Aufgaben zum Thema: Daten ändern