Can I create a database constraint on a TEXT column in SQLite disallowing the value of the column to be empty string ""?
I want to allow the column to be null, but disallow empty string.
Yes you can:
sqlite> create table foo (bar TEXT, CHECK(bar <> ''));
sqlite> insert into foo values (NULL);
sqlite> insert into foo values ('bla');
sqlite> insert into foo values ('');
Error: constraint failed
You can use a CHECK constraint (http://www.sqlite.org/lang_createtable.html):
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> create table example(col, CHECK (col is null or length(col) > 0));
sqlite> insert into example values ('');
SQL error: constraint failed
sqlite> insert into example values (null);
sqlite> insert into example values ('sample');
sqlite> .nullvalue NULL
sqlite> select col from example;
NULL
sample
As far as i know doesn't exist a similar constraint in SQLite, but maybe you can workaround with a Trigger that on INSERT and/or UPDATE automatically change the string empty in NULL.
Related
these both statements seem to make a difference, but I do not yet get why:
ALTER TABLE FOO ADD COLUMN DELETED BOOLEAN NOT NULL DEFAULT FALSE
seems to behave differently than:
ALTER TABLE FOO ADD COLUMN DELETED BOOLEAN NOT NULL DEFAULT 0
can anyone shed some light on this - I thought FALSE is 0 and TRUE is 1 - but this boolean seems to have >= 4 states:
➜ ~ sqlite3
SQLite version 3.8.7.4 2014-12-09 01:34:36
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> CREATE TABLE FOO ( id INTEGER );sqlite> INSERT INTO FOO ( id ) VALUES (1);
sqlite> select * from FOO;
1
sqlite> ALTER TABLE FOO ADD COLUMN DELETED BOOLEAN NOT NULL DEFAULT FALSE;sqlite> select * from FOO;
1|FALSE
sqlite> ALTER TABLE FOO ADD COLUMN DELETED2 BOOLEAN NOT NULL DEFAULT 0;
sqlite> select * from FOO;
1|FALSE|0
sqlite> ALTER TABLE FOO ADD COLUMN DELETED3 BOOLEAN NOT NULL DEFAULT TRUE;
sqlite> select * from FOO;
1|FALSE|0|TRUE
sqlite> ALTER TABLE FOO ADD COLUMN DELETED4 BOOLEAN NOT NULL DEFAULT 1;
sqlite> select * from FOO;
1|FALSE|0|TRUE|1
sqlite> select * from FOO WHERE DELETED;
sqlite> select * from FOO WHERE DELETED2;
sqlite> select * from FOO WHERE DELETED3;
sqlite> select * from FOO WHERE DELETED4;
1|FALSE|0|TRUE|1
Why exactly SQLite allows these ALTER TABLE statements to run as shown I don't know but the missing piece of the puzzle here is that those FALSE and TRUE values will be stored as strings.
Try this in the SQLite command line tool:
CREATE TABLE test (id integer, xx boolean not null default TRUE);
INSERT INTO test (id) VALUES (1)
.dump
You'll get this output:
sqlite> .dump
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE test (id integer, xx boolean not null default TRUE);
INSERT INTO "test" VALUES(1,'TRUE');
COMMIT;
As you can see, the TRUE value there is stored as a string.
Now, let's try to query for the TRUE value:
SELECT * FROM test WHERE xx = TRUE
this gives this error message:
Error: no such column: TRUE
So in short, TRUE or FALSE are not magical constants in SQLite SQL syntax for the boolean values. Why the ALTER TABLE statements allow for them to be specified without quotes I don't know, there's probably a good reason.
Here's the example from my comment:
ALTER TABLE test ADD COLUMN xy INTEGER NOT NULL DEFAULT MONKEYDOODLE;
Output from .dump:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE test (id integer, xx boolean not null default TRUE, xy INTEGER NOT
NULL DEFAULT MONKEYDOODLE);
INSERT INTO "test" VALUES(1,'TRUE','MONKEYDOODLE');
COMMIT;
One final piece of the puzzle is also that SQLite doesn't really prevent you from storing values of different data types in the same column.
From the documentation:
Any column in an SQLite version 3 database, except an INTEGER PRIMARY KEY column, may be used to store a value of any storage class.
You can see this in effect here:
CREATE TABLE test (id integer);
INSERT INTO test VALUES (1);
INSERT INTO test VALUES ('test');
INSERT INTO test VALUES (DATE());
INSERT INTO test VALUES (10.5);
This is the output from .dump:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE test (id integer);
INSERT INTO "test" VALUES(1);
INSERT INTO "test" VALUES('test');
INSERT INTO "test" VALUES('2015-07-20');
INSERT INTO "test" VALUES(10.5);
COMMIT;
When I run sqlite3 foo.db from cmd (Windows) and enter these commands (assuming TABLE 'test' does not exist):
sqlite> CREATE TABLE test (id integer PRIMARY KEY, name char(1));
sqlite> INSERT INTO test (name) VALUES ('aaaaaa');
there are no errors. To verify,
//Input
sqlite> SELECT * FROM test;
//Output
1|aaaaaa
Again, to verify,
sqlite> .schema test
CREATE TABLE test (id integer PRIMARY KEY, name char(1)); //output
and the schema isn't changed.
Is there something wrong, especially with the name char(1) part? For the record, I compiled SQLite3 using MinGW64 with
--host=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw // where /mingw is included in my PATH
Thanks in advance.
As there is no types in SQLite, the question is meaningless. All TEXT values are the same and are stored as "unlimited" (up to SQLITE_MAX_LENGTH) length strings.
What you see is a WAD: "working as designed".
SQLite doesn't enforce the length of a char(n) or varchar(n) column as it's declared in a CREATE TABLE statement. But you can enforce length restrictions using a CHECK constraint.
sqlite> create table test (
...> id integer primary key,
...> name char(1),
...> check (length(name)<=1)
...> );
sqlite> INSERT INTO test (name) VALUES ('aaaaaa');
Error: CHECK constraint failed: test
I tested the following cases.
CHECK is applied to an INTEGER column. It doesn't work.
sqlite> CREATE TABLE log (_id INTEGER PRIMARY KEY, timestamp INTEGER NOT NULL, message TEXT NOT NULL, status INTEGER NOT NULL CHECK (status IN (1, 0));
Error: near ";": syntax error
CHECK is applied to a TEXT column. It works.
sqlite> CREATE TABLE log (_id INTEGER PRIMARY KEY, timestamp INTEGER NOT NULL, message TEXT NOT NULL CHECK (message IN ('Bad', 'OK')), status INTEGER NOT NULL);
sqlite> insert into log values (3, 11111, 'OK', 1);
sqlite> select * from log;
3|11111|OK|1
sqlite> insert into log values (3, 11111, 'dsvsdvOK', 1);
Error: constraint failed
Both cases should work if I understand the documentation correctly.
column-constraint
expr
The first CREATE TABLE statement has three opening but only two closing parentheses.
Here is a simple shema:
sqlite> .schema recordtypes
CREATE TABLE recordtypes (record_id text primary key);
sqlite> .schema headers
CREATE TABLE headers (header_id text primary key);
sqlite> .schema record_to_headers
CREATE TABLE record_to_headers (id INTEGER, recordid TEXT, headerid TEXT, FOREIGN KEY(recordid) REFERENCES recordtypes(record_id), FOREIGN KEY(headerid) REFERENCES headers(header_id));
Then I insert values into recordtypes and then in record_to_headers:
sqlite> insert into recordtypes values("test");
sqlite> insert into record_to_headers values (1, "test", "yeah");
Then I remove the "test" from recordtypes table expecting it is removed from record_to_headers table also but this never happens:
sqlite> delete from recordtypes where record_id = "test";
sqlite> select * from recordtypes;
sqlite> select * from record_to_headers;
1|test|yeah
I need behavior if I remove the value from recordtypes table it is also removed from record_to_header table. Please advice how to do so. Thanks a lot.
Not that much experience with SQLLite, but from the documentation I can see, that SQLLite supports foreign key cascading. That would delete the child row when parent row is deleted:
FOREIGN KEY(headerid) REFERENCES headers(header_id) ON DELETE CASCADE
You should consult the documentation to see whether you need to configure something beforehand in SQLLite.
How to crate a now row without knowing the any of the columns of the table and using default values therefore?
In sqlite3 I simply do:
sqlite> CREATE TABLE t ("id" INTEGER PRIMARY KEY, "text" TEXT DEFAULT "hello world");
sqlite> INSERT INTO t DEFAULT VALUES;
sqlite> SELECT * FROM t;
1|hello world
But in sqlite2.8.17 I get:
sqlite> INSERT INTO t DEFAULT VALUES;
SQL error near 'DEFAULT': Syntax error.
Is there a way to do this right in sqlite2 or do I need to give the values manually in the insert statement?
You have to specify at least one value; all the others will then get their default values.
The rowid automatically gets a value when you specify NULL, so you can use that one:
INSERT INTO t(id) VALUES(NULL);