Okay, SQLite doesn't have a separate Boolean datatype, but it's not uncommon to use an INTEGER to store one. How can we toggle this value in a single SQL statement without retrieving stored value first?
For example, we have a table people with contents:
| id | name | is_friend |
|---|---|---|
| 1 | Peter | 0 |
| 2 | Mary | 1 |
| 3 | John | 0 |
To toggle Mary's is_friend property we can execute this SQL statement:
UPDATE `people` SET is_friend = ((is_friend | 1) - (is_friend & 1)) WHERE id = 2
Of cause in order for this to work is_friend column must be limited to store either 0 or 1. Make sure that you properly initialize you boolean column whilst creating a table by introducing a DEFAULT value (0) and validating CHECK expression:
CREATE TABLE `people` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`name` TEXT NOT NULL,
`is_friend` INTEGER NOT NULL DEFAULT 0 CHECK(is_friend IN (0,1))
);
Unfortunately SQLite does not allow adding DEFAULT nor CHECK attributes to existing tables. This is why we have to create a temporary table, copy contents into it, drop existing table and then rename newly created one:
-- begin transaction
BEGIN;
-- create a new table with proper structure
CREATE TABLE `people_proper` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`name` TEXT NOT NULL,
`is_friend` INTEGER NOT NULL DEFAULT 0 CHECK(is_friend IN (0,1))
);
-- copy data from old table
INSERT INTO `people_proper`
SELECT
`id`,
`name`,
-- make all invalid data to default to 0 (false)
(CASE WHEN is_friend NOT IN(0,1) THEN 0 ELSE is_friend END) AS `is_friend`
FROM `people`;
-- drop old table
DROP TABLE `people`;
-- rename new table
ALTER TABLE `people_proper` RENAME TO `people`;
-- commit transaction
COMMIT;