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
[email protected]
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users