How can there be duplicate rows with same primary key in SQLite? - sqlite

I have the following SQLite db:
sqlite> .schema
...
CREATE TABLE history (
date_created DATETIME,
date_updated DATETIME,
id INTEGER NOT NULL,
...
PRIMARY KEY (id),
FOREIGN KEY ... ,
...
);
...
sqlite> SELECT * FROM pragma_table_info('history');
0|date_created|DATETIME|0||0
1|date_updated|DATETIME|0||0
2|id|INTEGER|1||1
...
Even though the primary key is id, doing a query on it leads to duplicate values:
sqlite> select rowid, id, date_updated from history;
...
499|499|2021-03-12 18:45:46.433
500|500|2021-03-12 18:47:49.616
501|501|2021-03-12 18:47:50.322
500|500|2021-03-12 19:37:14.320
501|501|2021-03-12 19:37:15.153
Total row count also somehow 503.
How can this even be possible? I have a server running on SQLAlchemy to use this DB, if that makes any difference.

Related

sqlite column constraints both unique and foreign

Does sqlite allow a column to be both unique and a foreign key at the same time?
How does the definition look like?
CREATE TABLE table1 (
id INTEGER PRIMARY KEY,
fkey INTEGER NOT NULL UNIQUE REFERENCES table2(id)
)
CREATE TABLE table2 (
id INTEGER PRIMARY KEY
)
Sure
CREATE TABLE table1 (
id INTEGER PRIMARY KEY,
fkey INTEGER NOT NULL UNIQUE,
FOREIGN KEY(fkey) REFERENCES table2(id)
)
result.
Query executed successfully: CREATE TABLE table1 (
id INTEGER PRIMARY KEY,
fkey INTEGER NOT NULL UNIQUE,
FOREIGN KEY(fkey) REFERENCES table2(id)
) (took 0ms)
REMEMBER. As of version 3.6.19, SQLite supports foreign key constraints. But enforcement of foreign key constraints is turned off by default (for backwards compatibility). To enable foreign key constraint enforcement, run PRAGMA foreign_keys=ON, from http://sqlite.org/faq.html

foreign key mismatch on delete command for unrelated record

I have the following 5 tables defined with a few records inserted into the 1st 4. This is using sqlite 3.7.1.7 with foreign key constaint enabled.
create table if not exists subject (id varchar(50) primary key,desc varchar(100));
insert into subject (id,desc) values ("subject1","test subject");
create table if not exists subjectlevel (id_subject_id varchar(50) references subject(id) on delete cascade, id integer not null, desc varchar(100) not null, questmcmaxselections integer not null, primary key (id_subject_id,id));
insert into subjectlevel (id_subject_id,id,desc,questmcmaxselections) values ("subject1",1,"test subject1 level 1",4);
insert into subjectlevel (id_subject_id,id,desc,questmcmaxselections) values ("subject1",2,"test subject1 level 2",4);
create table if not exists questmc (id integer primary key, text varchar(300) not null, includeallanswers int not null, subject_id varchar(50), subjectlevel_id integer, foreign key (subject_id, subjectlevel_id) references subjectlevel (id_subject_id,id) on delete cascade);
insert into questmc (text,includeallanswers,subject_id,subjectlevel_id) values ("this is a _ question", 1, "subject1",1);
create table if not exists questmcselection (id integer primary key, text varchar(100) not null, subject_id varchar(50), subjectlevel_id integer, foreign key (subject_id, subjectlevel_id) references subjectlevel (id_subject_id,id) on delete cascade);
insert into questmcselection (text,subject_id,subjectlevel_id) values ("this is a solution","subject1",1);
create table if not exists questmc_questmcselection(id integer primary key, answer integer not null, questmc_id integer, questmcselection_id integer, subject_id varchar(50), subjectlevel_id integer, foreign key (questmc_id) references questmc(id) on delete cascade, foreign key (questmcselection_id) references questmcselection (id) on delete cascade, foreign key (subject_id,subjectlevel_id) references questmc (subject_id,subjectlevel_id) on delete cascade, foreign key (subject_id,subjectlevel_id) references questmcselection (subject_id,subjectlevel_id));
if i attempt to delete the second record in the subjectlevel table, i get a foreign key mismatch error as long as table questmc_questmcselection is defined.
sqlite> delete from subjectlevel where id=2;
Error: foreign key mismatch - "questmc_questmcselection" referencing "questmcselection"
questmc, questmcselection, and questmc_questmcselection have no related existing records that should prevent this deletion. Any idea why this error occurs?
This error has nothing to do with this particular subjectlevel record.
Your problem is that your tables lack the required indexes.
This was not reported earlier because that DELETE statement was the first command that required SQLite to check the consistency of the database schema.
Based on CL's answer -
sqlite> create table parent(a);
sqlite> create table child(a, FOREIGN KEY (a) REFERENCES parent(a));
sqlite> pragma foreign_keys = ON;
sqlite> insert into parent values(3);
sqlite> insert into child values (3);
Error: foreign key mismatch - "child" referencing "parent"
sqlite> create unique index p_a on parent(a);
sqlite> insert into child values (3);
sqlite> _
From the documentation:
Usually, the parent key of a foreign key constraint is the primary key
of the parent table. If [not], then the parent key columns must be
collectively subject to a UNIQUE constraint or have a UNIQUE index [which uses]
the collation sequences ... in the CREATE TABLE
statement for the parent table.
i.e. the alternative is:
sqlite> create table parent(a, b, UNIQUE (a, b));
sqlite> create table child (x, y, FOREIGN KEY (x, y) REFERENCES parent(a, b));
(this also highlights multi-column foreign keys; they work with indexes too...)

sqlalchemy foreign keys works only with primary key?

Tables and foreign keys are creating ok, but working not ok:
SQLite version 3.7.9 2011-11-01 00:52:41
sqlite> pragma foreign_keys=on;
sqlite>
sqlite> CREATE TABLE t1(id int primary key, uuid varchar(36));
sqlite> CREATE TABLE t2(id int primary key, t1_uuid varchar(36), FOREIGN KEY (t1_uuid) REFERENCES t1(uuid));
sqlite>
sqlite> INSERT INTO t1(uuid) values ("uuid-1");
sqlite> INSERT INTO t2(t1_uuid) values ("uuid-1");
Error: foreign key mismatch
But if i make t1(uuid) primary key, all works as expected:
sqlite> pragma foreign_keys=off;
sqlite> DROP TABLE t1;
sqlite> DROP TABLE t2;
sqlite> pragma foreign_keys=on;
sqlite> CREATE TABLE t1(id int, uuid varchar(36) primary key);
sqlite> CREATE TABLE t2(id int primary key, t1_uuid varchar(36), FOREIGN KEY (t1_uuid) REFERENCES t1(uuid));
sqlite> INSERT INTO t1(uuid) values ("uuid-1");
sqlite> INSERT INTO t2(t1_uuid) values ("uuid-1");
Creating an index doing nothing:
sqlite> pragma foreign_keys=on;
sqlite> CREATE TABLE t1(id int primary key, uuid varchar(36));
sqlite> CREATE INDEX uuindex ON t1(uuid);
sqlite> CREATE TABLE t2(id int primary key, t1_uuid varchar(36), FOREIGN KEY (t1_uuid) REFERENCES t1(uuid));
sqlite> INSERT INTO t1(uuid) values ("uuid-1");
sqlite> INSERT INTO t2(t1_uuid) values ("uuid-1");
Error: foreign key mismatch
The documentation says:
Usually, the parent key of a foreign key constraint is the primary key of the parent table. If they are not the primary key, then the parent key columns must be collectively subject to a UNIQUE constraint or have a UNIQUE index.

Is it allowed to have null foreign key in sqlite when PRAGMA foreign_keys=ON?

according to this null foreign keys are allowed unless and until we are adding the appropriate "NOT NULL" constraint to the schema.
but I am seeing the some different behavior,
sqlite> PRAGMA Foreign_keys;
1
sqlite> create table proc (
sqlite> pid integer,
sqlite> name text,
sqlite> ppid integer,
sqlite> foreign key (ppid) references proc (id)
sqlite> );
sqlite> .schema proc
CREATE TABLE proc (
pid integer,
name text,
ppid integer,
foreign key (ppid) references proc (id)
);
sqlite> insert into proc (pid, name, ppid)
sqlite> values (0, "init", null);
Error: foreign key mismatch
sqlite> PRAGMA Foreign_keys=OFF;
sqlite> PRAGMA Foreign_keys;
0
sqlite> insert into proc (pid, name, ppid)
sqlite> values (0, "init", null);
sqlite> select * from proc;
0|init|
how can I allow null foreign key in sqlite when PRAGMA foreign_keys=ON? or it is not possible at all?
The ID column is named pid, not id.
The parent key column must have a UNIQUE or PRIMARY KEY constraint.
Try adding a foreign key clause by changing your table create statement to:
CREATE TABLE proc (pid integer, name text, ppid integer, foreign key (ppid) references
proc (id) ON UPDATE CASCADE ON DELETE SET NULL);

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