(Sqlite3) Autoincrement-ID beim Einfügen erhalten

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
alan
User
Beiträge: 81
Registriert: Dienstag 10. April 2007, 11:30

Montag 3. September 2007, 11:07

Hallo

Ich bastle immer noch an meiner sqlite-Db :)

Ich habe zwei Tabellen, books und stats. stats ist mit books über ein Feld book_id verknüpft. In books ist das ein primary key und ich muss mich nicht drum kümmern, aber in stats muss ich selbst dafür sorgen, dass die richtige id eingetragen wird.

Mein Problem ist:
Mit executemany werden eine Menge neuer Bücher in books eingefügt.
Da es über die noch keine Daten gibt, sollen in stats Standardwerte eingefügt werden, verknüpft mit den "neuen" IDs.

Man könnte jetzt über die größte vorhandene ID vor dem Einfügen der neuen Bücher in die DB und die bekannte Anzahl der eingefügten Bücher die neuen IDs herausbekommen. Aber mir gefällt das nicht allzusehr.
Gibt es noch eine andere Möglichkeit, nach dem Einfügen die entsprechenden IDs direkt von sqlite3 zu erhalten? (Ich kann mich nicht darauf verlassen, dass irgendein anderes Feld oder eine beliebige Kombination anderer Felder außer ID einzigartige Werte beinhalten.)
BlackJack

Montag 3. September 2007, 11:52

Das naheliegendste wäre wohl eine Abfrage, die alle `book_id`\s liefert zu denen kein Eintrag in der `stats`-Tabelle existiert.

Ungetestet:

Code: Alles auswählen

SELECT books.book_id
FROM books
WHERE NOT EXISTS (
    SELECT stats.book_id
    FROM stats
    WHERE stats.book_id == books.book_id
);
Mit SQLite habe ich noch nichts komplizierteres gemacht, aber bei grösseren DBs gibt's sicher auch Wege über Trigger die angestossen werden wenn ein neuer Datensatz eingetragen wird.

Edit: Das geht auch in SQLite. Folgende Vorbereitung:

Code: Alles auswählen

DROP TABLE IF EXISTS books;
DROP TABLE IF EXISTS stats;
DROP TRIGGER IF EXISTS auto_stats;

CREATE TABLE books (
    book_id     INTEGER PRIMARY KEY,
    title       TEXT
);

CREATE TABLE stats (
    stat_id     INTEGER PRIMARY KEY,
    book_id     INTEGER UNIQUE,
    some_value  INTEGER DEFAULT 0
);

CREATE TRIGGER auto_stats AFTER INSERT ON books
    FOR EACH ROW BEGIN
        INSERT INTO stats (stat_id, book_id) VALUES (NULL, new.book_id);
    END;
Session:

Code: Alles auswählen

sqlite> .read test.sql
sqlite> SELECT * FROM books;
sqlite> SELECT * FROM stats;
sqlite> INSERT INTO books (book_id, title) VALUES (NULL, 'Python kurz & gut');
sqlite> SELECT * FROM books;
1|Python kurz & gut
sqlite> SELECT * FROM stats;
1|1|0
sqlite>
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Montag 3. September 2007, 13:15

Hallo!

Da war BlackJack ein wenig schneller. :D

Na gut, dann hier eine Möglichkeit ohne Trigger:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

try:
    from pysqlite2 import dbapi2 as sqlite3
except ImportError:
    import sqlite3


conn = sqlite3.connect(":memory:")

# Tabellen erstellen
sql = """
CREATE TABLE testtabelle1 (
  id INTEGER PRIMARY KEY,
  wert TEXT
);
CREATE TABLE testtabelle2 (
  id INTEGER PRIMARY KEY,
  referenz INTEGER NOT NULL,
  wert TEXT
);
"""
conn.executescript(sql)
conn.commit()

# Mit expliziter ID befüllen
data = (
    (10, u"Hallo", ),
    (20, u"Welt.", ),
)
sql = """
INSERT INTO testtabelle1 (id, wert) VALUES (?, ?)
"""
sql2 = """
INSERT INTO testtabelle2 (referenz, wert) VALUES (?, ?)
"""
for dataitem in data:
    cur = conn.execute(sql, dataitem)
    conn.execute(sql2, (cur.lastrowid, u"Hallo Welt %i" % cur.lastrowid))
conn.commit()

# Ohne explizite ID befüllen
data = (
    (u"Hallo", ),
    (u"Welt.", ),
)
sql = """
INSERT INTO testtabelle1 (wert) VALUES (?)
"""
for dataitem in data:
    cur = conn.execute(sql, dataitem)
    conn.execute(sql2, (cur.lastrowid, u"Hallo Welt %i" % cur.lastrowid))
conn.commit()

# Daten ausgeben
sql = """
SELECT 
  t1.id, t1.wert, t2.id, t2.referenz, t2.wert
FROM
  testtabelle1 t1 OUTER JOIN testtabelle2 t2 ON t1.id = t2.referenz
"""
cur = conn.execute(sql)
print u"t1.id t1.wert   t2.id t2.referenz t2.wert"
print "-" * 60
for row in cur:
    print "%-6s%-10s%-6s%-12s%-10s" % row
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
alan
User
Beiträge: 81
Registriert: Dienstag 10. April 2007, 11:30

Montag 3. September 2007, 17:11

Danke!
Antworten