On Sun, Jun 10, 2012 at 02:35:20PM +0200, Wolfgang Meiners wrote: > Hello, > > i have written a sqlite3-db for a small books library. Within this db > there is a table: > sqlite> .schema ausleihen > CREATE TABLE ausleihen ( > aid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, > pid INTEGER NOT NULL, > beid INTEGER NOT NULL, > ausleihdatum DATE NOT NULL, > rueckgabe DATE, > FOREIGN KEY(pid) REFERENCES personen (pid) ON DELETE CASCADE, > FOREIGN KEY(beid) REFERENCES buchexemplare (beid) ON DELETE CASCADE > ); > CREATE INDEX ix_ausleihen_ausleihdatum ON ausleihen (ausleihdatum); > CREATE TRIGGER insertausleihe > BEFORE INSERT ON ausleihen > FOR EACH ROW > BEGIN > SELECT CASE > WHEN EXISTS (SELECT * FROM ausleihen > WHERE (beid = NEW.beid) AND (rueckgabe is\ > NULL)) > THEN RAISE(ROLLBACK, 'Buch ist ausgeliehen') > END; > SELECT CASE > WHEN NOT EXISTS (SELECT * FROM personen > WHERE pid = NEW.pid) > THEN RAISE(ROLLBACK, 'Person existiert nicht') > END; > SELECT CASE > WHEN NOT EXISTS (SELECT * FROM buchexemplare > WHERE beid = NEW.beid) > THEN RAISE(ROLLBACK, 'Buchexemplar existiert nicht') > END; > END; > sqlite> > > In this table, every row belongs to a person (pid) which has an exemplar > of a certain book on loan (beid). If the bookexemplar is on loan, the > value rueckgabe is equal to NULL. The first SELECT statement in the > trigger raises a rollback, if the book is already on loan. > > This works, but there is an issue with the orm-part of sqlalchemy: Since > sqlalchemy.orm does not 'see' this trigger, the following python > function returns true, even if the trigger is violated: > > def buchausleihen(session, pid, beid, ausleihdatum=None): > T try: > session.add(Ausleihe(pid=pid, beid=beid, > ausleihdatum=ausleihdatum)) > return True > except: > return False > > This means: > (python code:) > print(buchausleihen(session,pid=1,beid=1)) # True > print(buchausleihen(session,pid=2,beid=1)) # True > > session.commit() # raises an error > > This is not what i expected. So i think, if i could write an integrity > constraint - maybe an CHECK-clause, this would be seen by sqlalchemy. > > So my question is: (how) can i write an integrity constraint in sqlite3 > (version 3.6.12) which is equivalent to the part > SELECT CASE > WHEN EXISTS (SELECT * FROM ausleihen > WHERE (beid = NEW.beid) AND (rueckgabe is\ > NULL)) > THEN RAISE(ROLLBACK, 'Buch ist ausgeliehen') > END; > of the trigger?
Why not add a unique index on ausleihen(beid,rueckgabe). That way, the book identified by beid cannot be inserted twice into the ausleihen table if the current book is on loan. However, you'd need a non-NULL sentinal value for rueckgabe for this to work, perhaps some epoch that is before any valid return time, such that a book is considered on loan if rueckgabe = sentinal value. Your foreign key constraints take care of ensuring the book and person exist. The unique index deals with the book only being loaned once at a time, so you can discard the trigger completely. So you'd have: CREATE TABLE ausleihen ( aid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, pid INTEGER NOT NULL, beid INTEGER NOT NULL, ausleihdatum DATE NOT NULL, rueckgabe DATE NOT NULL DEFAULT 0, -- 0 is sentinal to indicate not returned instead of NULL CONSTRAINT Leihgabe_Scheck UNIQUE (beid,rueckgabe), FOREIGN KEY(pid) REFERENCES personen (pid) ON DELETE CASCADE, FOREIGN KEY(beid) REFERENCES buchexemplare (beid) ON DELETE CASCADE ); Hope that helps, Christian _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users