how do I override the autoincremented primary key when doing an insert - sqlite

In MS SQL I would use
SET IDENTITY INSERT ON
How do I do something similar in SQLite. I am trying to upgrade a database and want to maintain the IDs from the original
Thanks

You don't need to set IDENTITY INSERT, because it is always possible to set the value explicitly. With SQLite, you can just insert into the ROWID column:
drop table test;
create table test(name varchar);
insert into test(name) values('Hello');
insert into test(rowid, name) values(10, 'World');
select rowid, name from test;
The same if you use an autoincrement primary key:
drop table test;
create table test(id integer primary key autoincrement, name varchar);
insert into test(name) values('Hello');
insert into test values(10, 'World');
select * from test;
See also http://www.sqlite.org/autoinc.html

Related

Insert the id from a previous query inside a sqlite trigger

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

why content_rowid must be integer in FTS?

Why content_rowid must be integer in FTS?
And what if content_rowid be a not primary integer key?
I create a VIRTUAL TABLE and TRIGGER width content_rowid equal to a not primary integer key, it works, has there any hidden risk?
CREATE TABLE tbl (a, createTime INTEGER NOT NULL);
CREATE VIRTUAL TABLE fts USING fts5(a, content=tbl, content_rowid=createTime);
CREATE TRIGGER IF NOT EXISTS tbl_ai AFTER INSERT ON tbl
BEGIN
INSERT INTO fts (rowid, a)
VALUES (new.createTime, new.a);
END;
Is there anywayt to set content_rowid to a text column?I have tried,throw error dataType mismatch
CREATE TABLE tbl (a, guid text NOT NULL PRIMARY KEY);
CREATE VIRTUAL TABLE fts USING fts5(a, content=tbl, content_rowid=guid);
CREATE TRIGGER IF NOT EXISTS tbl_ai AFTER INSERT ON tbl
BEGIN
INSERT INTO fts (rowid, a)
VALUES (new.guid, new.a);
END;
Your virtual table explicitly references tbl.createTime, which is an integer. The resulting virtual column is of the same type, necessarily.

Delete row and referencing rows in another table in SQLite 3

I'm using SQLite to play around and learn some more SQL. I have a SQLite 3 database populated like this:
create table playlist (id integer primary key autoincrement, name text);
create table playlistitem (id integer primary key autoincrement,
playlist_id integer, name text);
insert into playlist (name) values ("Moss");
insert into playlist (name) values ("Jen");
insert into playlistitem (playlist_id, name) values (1, "Roy");
insert into playlistitem (playlist_id, name) values (1, "Richmond");
insert into playlistitem (playlist_id, name) values (2, "Denholm");
Great, now I have two playlist items in the "Moss" playlist, "Roy" and "Richmond"; I have one item in the "Jen" playlist: "Denholm".
What I'd like to do is delete the "Moss" playlist and all of its items with a single query.
I saw something like this, which fails for me:
delete playlist, playlistitem from playlist
inner join playlistitem on playlistitem.playlist_id = playlist.id
where playlist.name = "Moss";
Failure:
Error: near "playlist": syntax error
What am I doing wrong?
sqlite doesn't support join in delete statement. You have to use separate query that deletes from second table based on playlist_id, making a delete trigger on playlist, or make that reference a foreign key with on delete cascade:
create table playlistitem (
id integer primary key autoincrement,
playlist_id integer, name text,
foreign key(playlist_id) references playlist(id) on delete cascade);
and then just using delete from playlist where name='Moss'.
Don't forget to enable foreign keys - pragma foreign_keys=1 (you have to re-enable this on each sqlite connection, e.g. as the first command after connecting).

How to have an automatic timestamp in SQLite?

I have an SQLite database, version 3 and I am using C# to create an application that uses this database.
I want to use a timestamp field in a table for concurrency, but I notice that when I insert a new record, this field is not set, and is null.
For example, in MS SQL Server if I use a timestamp field it is updated by the database and I don't have to set it by myself. Is this possible in SQLite?
Just declare a default value for a field:
CREATE TABLE MyTable(
ID INTEGER PRIMARY KEY,
Name TEXT,
Other STUFF,
Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
);
However, if your INSERT command explicitly sets this field to NULL, it will be set to NULL.
You can create TIMESTAMP field in table on the SQLite, see this:
CREATE TABLE my_table (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name VARCHAR(64),
sqltime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
INSERT INTO my_table(name, sqltime) VALUES('test1', '2010-05-28T15:36:56.200');
INSERT INTO my_table(name, sqltime) VALUES('test2', '2010-08-28T13:40:02.200');
INSERT INTO my_table(name) VALUES('test3');
This is the result:
SELECT * FROM my_table;
Reading datefunc a working example of automatic datetime completion would be:
sqlite> CREATE TABLE 'test' (
...> 'id' INTEGER PRIMARY KEY,
...> 'dt1' DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime')),
...> 'dt2' DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now', 'localtime')),
...> 'dt3' DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime'))
...> );
Let's insert some rows in a way that initiates automatic datetime completion:
sqlite> INSERT INTO 'test' ('id') VALUES (null);
sqlite> INSERT INTO 'test' ('id') VALUES (null);
The stored data clearly shows that the first two are the same but not the third function:
sqlite> SELECT * FROM 'test';
1|2017-09-26 09:10:08|2017-09-26 09:10:08|2017-09-26 09:10:08.053
2|2017-09-26 09:10:56|2017-09-26 09:10:56|2017-09-26 09:10:56.894
Pay attention that SQLite functions are surrounded in parenthesis!
How difficult was this to show it in one example?
Have fun!
you can use triggers. works very well
CREATE TABLE MyTable(
ID INTEGER PRIMARY KEY,
Name TEXT,
Other STUFF,
Timestamp DATETIME);
CREATE TRIGGER insert_Timestamp_Trigger
AFTER INSERT ON MyTable
BEGIN
UPDATE MyTable SET Timestamp =STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') WHERE id = NEW.id;
END;
CREATE TRIGGER update_Timestamp_Trigger
AFTER UPDATE On MyTable
BEGIN
UPDATE MyTable SET Timestamp = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') WHERE id = NEW.id;
END;
To complement answers above...
If you are using EF, adorn the property with Data Annotation [Timestamp], then
go to the overrided OnModelCreating, inside your context class, and add this Fluent API code:
modelBuilder.Entity<YourEntity>()
.Property(b => b.Timestamp)
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken()
.ForSqliteHasDefaultValueSql("CURRENT_TIMESTAMP");
It will make a default value to every data that will be insert into this table.
you can use the custom datetime by using...
create table noteTable3
(created_at DATETIME DEFAULT (STRFTIME('%d-%m-%Y %H:%M', 'NOW','localtime')),
title text not null, myNotes text not null);
use 'NOW','localtime' to get the current system date else it will show some past or other time in your Database after insertion time in your db.
Thanks You...
If you use the SQLite DB-Browser you can change the default value in this way:
Choose database structure
select the table
modify table
in your column put under 'default value' the value: =(datetime('now','localtime'))
I recommend to make an update of your database before, because a wrong format in the value can lead to problems in the SQLLite Browser.

sqlite - How to get INSERT OR IGNORE to work

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.

Resources