In a sqlite3 database I would like to create a trigger on a view so that I can insert data over the view. Inside the trigger I would like to insert something in the tblmedia table. The id of the inserted row should be now also inserted into the tblbook as id.
In sqlite there are no variables. Otherwise I would store the returning value in the variable and would use it in the second query.
Can this even be achieved in sqlite?
Following my sql schema:
CREATE TABLE tblmedia(
id INTEGER PRIMARY KEY NOT NULL,
title VARCHAR NOT NULL,
raiting INTEGER,
file_name VARCHAR NOT NULL,
media_type TEXT NOT NULL
);
CREATE TABLE tblbook(
id INTEGER PRIMARY KEY NOT NULL,
author VARCHAR,
FOREIGN KEY (id) REFERENCES tblmedia(id) ON DELETE CASCADE
);
CREATE VIEW book AS
SELECT
m.id as id,
m.title as title,
b.author as author,
m.raiting as raiting,
m.file_name as file_name
FROM tblbook b
LEFT JOIN tblmedia m ON m.id = b.id;
CREATE TRIGGER insert_book
INSTEAD OF INSERT ON book
BEGIN
INSERT INTO tblmedia(title, raiting, file_name)
VALUES(new.title, new.raiting, new.file_name);
INSERT INTO tblbook(id, author)
VALUES (xx, new.author); -- xx should be the id from the previous insert
END
I need to copy one table to another and both tables contain column with AUTOINCREMENT. Is it possible to insert a defined value into AUTOINCREMENT column.
Tables:
CREATE TABLE tmptimetables (
_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
_title NVARCHAR(256) NOT NULL,
_weeks INTEGER NOT NULL,
_first_week_date INTEGER NOT NULL,
_auto_complete INTEGER NOT NULL,
_first_lesson_time INTEGER NOT NULL,
_lesson_duration INTEGER NOT NULL,
_break_duration INTEGER NOT NULL,
_color INTEGER NOT NULL,
_symbol NCHAR(1) NOT NULL
);
CREATE TABLE timetables (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title NVARCHAR(256) NOT NULL,
weeks INTEGER NOT NULL,
first_week_date INTEGER NOT NULL,
auto_complete INTEGER NOT NULL,
first_lesson_time INTEGER NOT NULL,
lesson_duration INTEGER NOT NULL,
break_duration INTEGER NOT NULL,
color INTEGER NOT NULL,
symbol NCHAR(1) NOT NULL
);
My SQL request:
INSERT INTO timetables (
auto_complete,
break_duration,
color,
first_lesson_time,
first_week_date, id,
lesson_duration,
symbol,
title,
weeks
)
SELECT
_auto_complete,
_break_duration,
_color,
_first_lesson_time,
_first_week_date,
_id,
_lesson_duration,
_symbol,
_title,
_weeks
FROM tmptimetables
AUTOINCREMENT can only be used for a column that is INTEGER PRIMARY KEY, it is INTEGER PRIMARY KEY that is the factor that makes the column a special column whereby if the value is not provided when inserting a row that a unique integer will be assigned.
So be the column INTEGER PRIMARY KEY or INTEGER PRIMARY KEY AUTOINCREMENT you can specify an integer value and a row may be inserted with the given value.
A row will not be inserted with a given value if that value is not unique.
For example if the table timetables is currently :-
Then
INSERT INTO timetables (id,title,weeks,first_week_date,auto_complete,first_lesson_time,lesson_duration,break_duration,color,symbol) VALUES (null,'mytitle',78,86000,23,1800,900,200,16,'E');
Would insert a new row with the id as determined by SQLite's algorithm for providing a unique id (probably 5).
If the id were changed to be provided (i.e. not null) say to 10 as per :-
INSERT INTO timetables (id,title,weeks,first_week_date,auto_complete,first_lesson_time,lesson_duration,break_duration,color,symbol) VALUES (10,'mytitle',78,86000,23,1800,900,200,16,'E');
Then the id for the new row would be 10.
However if then using (the same SQL but with the last column value changed) :-
INSERT INTO timetables (id,title,weeks,first_week_date,auto_complete,first_lesson_time,lesson_duration,break_duration,color,symbol) VALUES (10,'mytitle',78,86000,23,1800,900,200,16,'Z');
A new row would not be inserted as a row with an id of 10 already exists.
Finally if the id is not given (null is used) but the SQL is otherwise the same a new row is inserted with a unique id being provided by SQLite e.g.
INSERT INTO timetables (id,title,weeks,first_week_date,auto_complete,first_lesson_time,lesson_duration,break_duration,color,symbol) VALUES (null,'mytitle',78,86000,23,1800,900,200,16,'Z');
So the end result of following the above is :-
AUTOINCREMENT
The AUTOINCREMENT keyword, only usable for an INTEGER PRIMARY COLUMN, invokes a different algorithm for determining the next sequence to ensure that the next sequence/id is always greater, whilst without AUTOINCREMENT a lower sequence/id can be applied.
The AUTOINCREMENT keyword does not specify that if a value for the column is not provided then a sequence/id is applied it is INTEGER PRIMARY KEY that specifies that. Well actually, by default, i.e. unless WITHOUT ROWID is specified, this happens for all tables. It's just the the special rowid column is hidden. Specifying <column_name> INTEGER PRIMARY KEY (where is a valid column name) creates an alias of the rowid.
For example using SELECT rowid,* FROM timetables produces :-
SQLite Autoincrement
Rowid Tables
It's my first time with sqlite and I wrote a simple database for storing and retrieving map tiles.
Here is the sqlite data base:
CREATE TABLE IF NOT EXISTS Tiles (id INTEGER NOT NULL PRIMARY KEY, X INTEGER NOT NULL, Y INTEGER NOT NULL, Zoom INTEGER NOT NULL, Type INTEGER NOT NULL,Date TEXT)
CREATE TABLE IF NOT EXISTS TilesData (id INTEGER NOT NULL PRIMARY KEY CONSTRAINT fk_Tiles_id REFERENCES Tiles(id) ON DELETE CASCADE, Tile BLOB NULL)
CREATE TRIGGER fki_TilesData_id_Tiles_id BEFORE INSERT ON [TilesData] FOR EACH ROW BEGIN SELECT RAISE(ROLLBACK, 'insert on table TilesData violates foreign key constraint fki_TilesData_id_Tiles_id') WHERE (SELECT id FROM Tiles WHERE id = NEW.id) IS NULL; END
CREATE TRIGGER fku_TilesData_id_Tiles_id BEFORE UPDATE ON [TilesData] FOR EACH ROW BEGIN SELECT RAISE(ROLLBACK, 'update on table TilesData violates foreign key constraint fku_TilesData_id_Tiles_id') WHERE (SELECT id FROM Tiles WHERE id = NEW.id) IS NULL; END
CREATE TRIGGER fkdc_TilesData_id_Tiles_id BEFORE DELETE ON Tiles FOR EACH ROW BEGIN DELETE FROM TilesData WHERE TilesData.id = OLD.id; END
Here is the insert operation:
INSERT INTO Tiles(X, Y, Zoom, Type,Date) VALUES(?, ?, ?, ?,?);
INSERT INTO TilesData(id, Tile) VALUES((SELECT last_insert_rowid()), ?);
Here is the read operation:
SELECT Tile FROM TilesData WHERE id = (SELECT id FROM Tiles WHERE X=%1 AND Y=%2 AND Zoom=%3 AND Type=%4)
The problem is, when the database is small the read is still very fast(around 20ms), but when the database becomes larger (around 15000 rows), the read access becomes very slow (around 4000ms).
Am I doing anything wrong? Any suggestions to improve the performance?
if you want for Android You can use also noSQL solution for speed. For example Couchbase
I'm trying to insert data into a table. I would like to insert the row if the column doesn't have the data already - regardless of the other columns.
CREATE TABLE t (
id INTEGER PRIMARY KEY,
name VARCHAR,
other INT
);
INSERT OR IGNORE INTO t (name) VALUES ('a');
INSERT OR IGNORE INTO t (name) VALUES ('a');
INSERT OR IGNORE INTO t (name) VALUES ('a');
With the above snippet I end up with 3 rows, not 1 as I would have thought. If it matters the actual sql is happening inside of a INSTEAD OF INSERT trigger, this is just a simple test case.
Replace
CREATE TABLE t (
id INTEGER PRIMARY KEY,
name VARCHAR,
other INT
);
with
CREATE TABLE t (
id INTEGER PRIMARY KEY,
name VARCHAR UNIQUE,
other INT
);
Then you will get
sqlite> CREATE TABLE t (
...> id INTEGER PRIMARY KEY,
...> name VARCHAR UNIQUE,
...> other INT
...> );
sqlite> INSERT OR IGNORE INTO t (name) VALUES ('a');
sqlite> INSERT OR IGNORE INTO t (name) VALUES ('a');
sqlite> INSERT OR IGNORE INTO t (name) VALUES ('a');
sqlite> select * from t ;
1|a|
That would only work for the primary key field or unique constraints:
The optional conflict-clause allows the specification of an
alternative constraint conflict resolution algorithm to use during
this one INSERT command.
Further:
The ON CONFLICT clause applies to UNIQUE and NOT NULL constraints
(and to PRIMARY KEY constraints which for the purposes of this section
are the same thing as UNIQUE constraints). The ON CONFLICT algorithm
does not apply to FOREIGN KEY constraints. There are five conflict
resolution algorithm choices: ROLLBACK, ABORT, FAIL, IGNORE, and
REPLACE. The default conflict resolution algorithm is ABORT.
I'm trying to solve the problem that composite keys in sqlite don't allow autoincrement.
I don't know if it's possible at all, but I was trying to store the last used id in a different table, and use a trigger to assign the next id when inserting a new reccord.
I have to use composite keys, because a single pk wouldn't be unique (because of database merging).
How can I set a field of the row being inserted based on a value in a different table
The query so far is:
CREATE TRIGGER pk BEFORE INSERT ON product_order
BEGIN
UPDATE auto_increment SET value = value + 1 WHERE `table_name` = "product_order";
END
This successfully updates the value. But now I need to assign that new value to the new record. (new.id).
If you use an AFTER INSERT trigger then you can update the newly inserted row, as in the following example.
CREATE TABLE auto_increment (value INT, table_name TEXT);
INSERT INTO auto_increment VALUES (0, 'product_order');
CREATE TABLE product_order (ID1 INT, ID2 INT, name TEXT);
CREATE TRIGGER pk AFTER INSERT ON product_order
BEGIN
UPDATE auto_increment
SET value = value + 1
WHERE table_name = 'product_order';
UPDATE product_order
SET ID2 = (
SELECT value
FROM auto_increment
WHERE table_name = 'product_order')
WHERE ROWID = new.ROWID;
END;
INSERT INTO product_order VALUES (1, NULL, 'a');
INSERT INTO product_order VALUES (2, NULL, 'b');
INSERT INTO product_order VALUES (3, NULL, 'c');
INSERT INTO product_order VALUES (4, NULL, 'd');
SELECT * FROM product_order;