I have a table with a INTEGER PRIMARY KEY
and several FOREIGN KEY
fields that point to other tables:
CREATE TABLE DifficultTable
(
id INTEGER NOT NULL UNIQUE,
name TEXT,
fooId INTEGER,
barId INTEGER,
PRIMARY KEY(id AUTOINCREMENT),
FOREIGN KEY(fooId) REFERENCES FooTable(id)
FOREIGN KEY(barId) REFERENCES BarTable(id)
);
CREATE TABLE FooTable
(
id INTEGER NOT NULL UNIQUE,
name TEXT NOT NULL UNIQUE,
PRIMARY KEY (id AUTOINCREMENT)
);
CREATE TABLE BarTable
(
id INTEGER NOT NULL UNIQUE,
name TEXT NOT NULL UNIQUE,
PRIMARY KEY (id AUTOINCREMENT)
);
To simplify this for the C-API that accesses it, I also provide this data in a VIEW
that resolves those foreign keys to the names and I supply a trigger to INSERT
:
CREATE VIEW SimpleView
AS
SELECT
DifficultTable.id,
DifficultTable.name,
FooTable.name AS foo,
BarTable.name AS bar
FROM
DifficultTable
LEFT JOIN
FooTable ON DifficultTable.fooId = FooTable.id
LEFT JOIN
BarTable ON DifficultTable.barId = BarTable.id;
CREATE TRIGGER SimpleInsert
AS
INSTEAD OF INSERT ON SimpleView
BEGIN
INSERT INTO DifficultTable(name, fooId, barId)
VALUES (NEW.name,
(SELECT id FROM FooTable WHERE name = New.foo),
(SELECT id FROM BarTable WHERE name = New.bar)
);
END;
If I insert a few values into FooTable
and BarTable
, I can confirm sqlite3_last_insert_rowid()
is working well:
sqlite> INSERT INTO FooTable(name) VALUES ("One"),("Two"),("Three"),("Four");
sqlite> SELECT last_insert_rowid();
4 <-- Good. There are now four rows in FooTable.
sqlite> INSERT INTO BarTable(name) VALUES ("One"),("Two");
sqlite> SELECT last_insert_rowid();
2 <-- Good. There are now two rows in BarTable
But if I insert into SimpleView
, the last_insert_rowid()
is not updated:
sqlite> INSERT INTO SimpleView (name, foo, bar) VALUES ("One", "Four", "Two");
sqlite> SELECT last_insert_rowid();
2 <-- Expected 1 because there is now 1 row in DifficultTable
Is there an easy way to get that rowid?
Summary of all data in the database after running these commands:
FooTable
id | name |
---|---|
1 | One |
2 | Two |
3 | Three |
4 | Four |
BarTable
id | name |
---|---|
1 | One |
2 | Two |
SimpleView
id | name | foo | bar |
---|---|---|---|
1 | One | Four | Two |
DifficultView
id | name | fooId | barId |
---|---|---|---|
1 | One | 4 | 2 |
I was hoping to use sqlite3_last_insert_rowid()
because it's just a 1-liner in C. I might be able to do another SQL Query, but is it guaranteed that id
will always increment (even if rows get deleted?)
SELECT id
FROM DifficultTable
ORDER BY id DESC
LIMIT 1
Here's an answer per Shawn's comments. Last Insert Rowid documentation says:
If an INSERT occurs within a trigger then this routine will return the rowid of the inserted row as long as the trigger is running. Once the trigger program ends, the value returned by this routine reverts to what it was before the trigger was fired.
This means you cannot use sqlite3_last_insert_rowid()
after completing an INSERT on a trigger. The alternative is performing a query:
SELECT id
FROM DifficultTable
ORDER BY id DESC
LIMIT 1
This will work fine unless the table fills up because of the description of AUTOINCREMENT
:
The usual algorithm is to give the newly created row a ROWID that is one larger than the largest ROWID in the table prior to the insert. ... If the largest ROWID is equal to the largest possible integer ... the database engine starts picking positive candidate ROWIDs at random until it finds one that is not previously used.
AUTOINCREMENT
isn't necessary. Using this keyword changes the description above to:
The ROWID chosen for the new row is at least one larger than the largest ROWID that has ever before existed in that same table