How does sqlite ON CONFLICT clause work in a column definition? - sqlite

I have the following example:
sqlite> create table FILES (FILENAME VARCHAR(1024) PRIMARY KEY NOT NULL ON CONFLICT IGNORE);
With this, I gather from the documentation that an insert that violates this primary key would be ignored.
But that's not happening, the 2. insert gives an error.
sqlite> insert into files values ('fileA');
sqlite> insert into files values ('fileA');
Error: UNIQUE constraint failed: FILES.FILENAME
So, how does ON CONFLICT IGNORE work in the above table, what is its purpose ?
(Note - I know I can also run insert or ignore into files values ('fileA');, and that will be ignored, but the question is about the column definition).

The conflict resolution clause applies to the NOT NULL constraint, so it would ignore only NULL values.
To ignore duplicates, add ON CONFLICT IGNORE directly after the PRIMARY KEY constraint.

Related

Error on adding PRIMARY KEY to existing table [duplicate]

I keep getting an error "Incorrect index name 'f7'" using MySQL and I've narrowed it down to the following:
First I create the table,
CREATE TABLE testTable (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
f7 INTEGER NOT NULL,
FOREIGN KEY (f7) REFERENCES testTable2 (id) ON DELETE CASCADE ON UPDATE CASCADE,
) ENGINE=InnoDB;
And then elsewhere,
ALTER TABLE testTable ADD UNIQUE f7;
This has led me to believe that this has to do with a duplicate index (?) I just can't figure out how to fix it. Many thanks.
Give it a name, so it doesn't conflict with the foreign Key index
ALTER TABLE `testtable` ADD UNIQUE INDEX `foo` (`f7`);
An incorrect index name error is given when you're attempting to create a new index with the same name as an existing index.
In MySQL, when you create a foreign key, as you're doing with FOREIGN KEY (f7) REFERENCES testTable2 (id) ON DELETE CASCADE ON UPDATE CASCADE, an index is auto-created as well. In this case, the name is defaulted to f7.
The foreign key is created as a non-unique index; your second command: ALTER TABLE testTable ADD UNIQUE (f7); will make this index unique - not add a second one.
To verify what indexes already exist on the table, you can use the following:
SHOW INDEXES FROM testTable;
If you're receiving this error, there is likely additional code elsewhere that is attempting to create an index named f7. You can attempt to find it, or change your CREATE TABLE syntax to name the key something different so that it doesn't cause conflicts:
FOREIGN KEY fk_testTable_f7 (f7) REFERENCES testTable2 (id) ON DELETE CASCADE ON UPDATE CASCADE
In this example, I used fk_testTable_f7 and you should now have a non-unique index on the table named fk_testTable_f7. To make it unique, you can use your existing ALTER command as you want the column to be unique - not the foreign key itself.

Is there any way to force SQLite constrains checks?

For example, let say DB has foreign key A.b_id -> B.id with SET NULL on delete.
If record with some B.id get deleted, all b_id references will be set to NULL.
But if A already contains record where A.b_id has value that is not in B.id (it was inserted without foreign keys support), is there a way to force SQLite DB check foreign keys and set to NULL such data?
In fact, in first place I'm solving an DB upgrading task.
On start app checks if internal DB (resource) has higher version than user DB.
If so it backups user DB, copies internal empty DB to user storage. Than turns off foreign keys support and fills new DB with data from backup, inserting automatically in loop table by table for all columns with same name. Turns on foreign keys support back.
Everything works fine, but if in some table in old DB there is no foreign key constrain previously, while new DB has one, the data will be inserted as is and link can point nowhere (possibly wrong links is unavoidable and not related to question).
Yes, I understand a way to insert without turning off foreign keys support, but it would need knowledge of tables dependencies order that I would like to avoid.
Thanks for any help in advance!
Although I don't know of a way that automatically will set to NULL all orphaned values of a column in a table that (should) reference another column in another table, there is a way to get a report of all these cases and then act accordingly.
This is the PRAGMA statement foreign_key_check:
PRAGMA schema.foreign_key_check;
or for a single table check:
PRAGMA schema.foreign_key_check(table-name);
From the documenation:
The foreign_key_check pragma checks the database, or the table called
"table-name", for foreign key constraints that are violated. The
foreign_key_check pragma returns one row output for each foreign key
violation. There are four columns in each result row. The first column
is the name of the table that contains the REFERENCES clause. The
second column is the rowid of the row that contains the invalid
REFERENCES clause, or NULL if the child table is a WITHOUT ROWID
table. The third column is the name of the table that is referred to.
The fourth column is the index of the specific foreign key constraint
that failed. The fourth column in the output of the foreign_key_check
pragma is the same integer as the first column in the output of the
foreign_key_list pragma. When a "table-name" is specified, the only
foreign key constraints checked are those created by REFERENCES
clauses in the CREATE TABLE statement for table-name.
Check a simplified demo of the way to use this PRAGMA statement, or its function counterpart pragma_foreign_key_check().
You can get a list of the rowids of all the problematic rows of each table.
In your case, you can execute an UPDATE statement that will set to NULL all the orphaned b_ids:
UPDATE A
SET b_id = NULL
WHERE rowid IN (SELECT rowid FROM pragma_foreign_key_check() WHERE "table" = 'A')
This also works in later versions of SQLite:
UPDATE A
SET b_id = NULL
WHERE rowid IN (SELECT rowid FROM pragma_foreign_key_check('A'))
but it does not seem to work up to SQLite 3.27.0

SQLlite: strange "Abort due to constraint violation"

I'm trying to rename a column of a table. I have a lot of tables with the word "couleur" and I renamed "manually" to "bulle".
I've successfully renamed main_groupecouleurs to main_groupebulles. Now i'm working on main_groupe. I'm trying to rename groupe_couleurs_id to groupe_bulles_id
The SQL is quite self-explaining:
BEGIN TRANSACTION;
DROP INDEX main_groupe_fc5cee5b;
CREATE TABLE main_groupe7e12
(
id INTEGER PRIMARY KEY NOT NULL,
description TEXT NOT NULL,
exemple TEXT,
groupe_bulles_id INTEGER DEFAULT NULL,
reference TEXT,
FOREIGN KEY (groupe_bulles_id) REFERENCES main_groupebulles(id)
DEFERRABLE INITIALLY DEFERRED
);
CREATE UNIQUE INDEX main_groupe_fc5cee5b ON main_groupe7e12 (groupe_bulles_id);
INSERT INTO main_groupe7e12(id, description, exemple, groupe_bulles_id, reference)
SELECT id, description, exemple, groupe_couleurs_id, reference
FROM main_groupe;
DROP TABLE main_groupe;
ALTER TABLE main_groupe7e12 RENAME TO main_groupe;
COMMIT;
When I run it, I get:
[SQLITE_CONSTRAINT] Abort due to constraint violation
(UNIQUE constraint failed: main_groupe7e12.groupe_bulles_id)
This means (I think I'm wrong here but I dont know what I'm missing) that it tries to insert some groupe_couleurs_id that are not in the referring table (= main_groupebulles). Thus I tried to see in the original table the problem:
SELECT * FROM main_groupe WHERE groupe_couleurs_id NOT IN (
SELECT id FROM main_groupebulles
);
I got no rows! What am I missing?
You have an UNIQUE index on your groupe_bulles_id column but based on the comments, there are a lot of valid duplicate values for that column coming from main_groupe.groupe_couleus_id and that causes the constraint violation.
Since having duplicate values is what you want, remove the UNIQUE from the CREATE UNIQUE INDEX ....

Altering a column on SQLite after definition

I was following an SQLite tutorial where the goal is to create a simple student database from an UML diagram.
The first thing I did was copy your UML, then took a break. Upon return, I figured I'd get started from the UML while reloading your video, so the very first things I did was create the student and sex_type table as so:
sqlite> create table student(name VARCHAR(23),
...> sex CHARACTER(1),
...> id_number INTEGER PRIMARY KEY);
sqlite> create table sex_type(sex_id TEXT PRIMARY KEY, sex_type INTEGER);
But then I realized, I forgot to indicated that I want sex_id to be NOT NULL as well. I also forgot under the to ensure that Foreign Key(sex) references sex_type(sex_id).
I reviewed my SQL books, and recalled something known as the ALTER command. However, no matter how I slice it, I get something along these lines:
sqlite> alter table sex_type MODIFY column sex_id TEXT PRIMARY KEY NOT NULL;
Error: near "MODIFY": syntax error
sqlite> alter table sex_type CHANGE column sex_id TEXT PRIMARY KEY NOT NULL;**
Error: near "CHANGE": syntax error
sqlite> alter table sex_type drop sex_id;
Error: near "DROP": syntax error
Always with the same supposed syntax error. About the only thing that has worked tonight:
sqlite> alter table sex_type RENAME TO gender;
sqlite> alter table gender_id RENAME TO sex_type;
So what is this syntax error that I'm overlooking, because going by my books my syntax should be fine. Do I have to insert something into these columns before modification can be done (which admittedly, I haven't tried yet)? Or am I missing something obvious about the ALTER/MODIFY/CHANGE/DROP command(s)?
SQLite's support for ALTER TABLE is pretty limited, including only RENAME TO and ADD_COLUMN. You're getting syntax errors because you're issuing a command that's not supported.
If you don't have any data to lose, you might be better of dropping and recreating the table.
If you do have data to lose, you might be better off renaming the table and creating a replacement using INSERT with SELECT, as seen in this example.

SQLite - How to insert to table with preliminary scan of the fields?

I use a database in my project and when i insert values ​​into a table i need to check if the field already has a value that does not produce an insert.
for exemple:
INSERT INTO myTable (column1) values ('some_value1')
if some_value1 alredy exists in column1 do not insert the value.
Put a unique constraint on myTable.column1. Then, whenever you try to insert a duplicate value, it won't let you as it violates the constraint. You can either catch and handle this error, or just let the DB engine do it's thing automatically.
EDIT: Note that SQLite doesn't allow you to do many alterations to your table, once it's created; so you may have to recreate your table with the constraint in place.
I believe this can be handled using the conflict resolution IGNORE method on SQLite. The code below should do the trick. The column1 here should be set to unique for this.
INSERT OR IGNORE INTO myTable (column1) values ('some_value1')
I'm using the following links for reference;
http://www.sqlite.org/lang_insert.html
http://www.sqlite.org/lang_conflict.html

Resources