Reputation: 2052
From my understanding, sqlite's datatype isn't associated to its column but to the data themselves: this practically means that you can insert any data to any column.
Is it possible to prohibit such a behaviour? I mean, I want sqlite to raise an error (or at least a warning) when I accidentally try to insert text to integer, for example.
Upvotes: 18
Views: 3510
Reputation: 164214
Since version 3.37.0 of SQLite it is possible to force data type checking with STRICT Tables:
In a CREATE TABLE statement, if the "STRICT" table-option keyword is added to the end, after the closing ")", then strict typing rules apply to that table.
You can use one of the following data types for the column definitions:
See a simplified demo.
Upvotes: 4
Reputation: 57083
I believe you could use a CHECK
constraint e.g.
CREATE TABLE testinsert (
COL1 INTEGER,
COL2 INTEGER CHECK (CAST(COL2||1 AS INTEGER) <> 0) -- column constraint
CHECK (CAST(COL1||1 AS INTEGER) <> 0) -- table constraint
);
both columns have the same constraint but applied to the columns differently
The constraint works by checking the value of the column when CAST to an INTEGER. The result will be 0 (false) if the value is not an INTEGER. However, to cater for 0 as a valid value 1 is concatenated to the column's value. Thus 0 will result in 1.
You could also use the TYPEOF
function e.g.
COL3 INTEGER CHECK(typeof(COL3) = 'INTEGER')
The following are some example INSERTS with the result :-
INSERT INTO testinsert VALUES(100,100); -- OK
INSERT INTO testinsert VALUES('100',100); -- OK
INSERT INTO testinsert VALUES('100','abc'); -- ouch for COL2 (abc)
INSERT INTO testinsert VALUES(0,100); -- OK
INSERT INTO testinsert VALUES('0',100); -- OK
INSERT INTO testinsert VALUES('abc',100); -- ouch for COL1 (abc)
With the COL3 added to the table :-
INSERT INTO testinsert VALUES(100,100,100); -- OK (all integers)
INSERT INTO testinsert VALUES('100','100',100); -- OK (CAST can accept integers as strings)
INSERT INTO testinsert VALUES('100','100','100'); -- Ouch typeof will consider '100' as a string, not an integer
If you wanted to ignore rather than abort (the default) then you could use :-
INSERT OR IGNORE INTO testinsert VALUES('100','abc'); -- insert Skipped - no fail
SQLite Manager was used for testing the above.
Here's an example of the CONFLICT failure :-
SQLiteManager: -- OK INSERT INTO testinsert VALUES('100','abc'); [ CHECK constraint failed: testinsert ] Exception Name: NS_ERROR_STORAGE_CONSTRAINT Exception Message: Component returned failure code: 0x80630003 (NS_ERROR_STORAGE_CONSTRAINT) [mozIStorageStatement.execute]
You may wish to have a look at :-
Upvotes: 6