VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
BOOL and BOOLEAN are spellings of TINYINT(1), which stores any number that fits in a byte. The column will hold 5 and -1 as readily as 0 and 1, and it gives them back exactly as they went in. VillageSQL’s vsql_boolean extension adds a STRICTBOOL column type that holds two values and refuses everything else.
Why TINYINT(1) bites
Here is the column MySQL gives you, with four rows inserted:TRUE. Both queries look correct and they disagree, because TRUE is the literal 1 and WHERE active tests for any non-zero value. A row holding 5 is active under one query and inactive under the other. Nothing in the schema stopped the 5 from being written, so the disagreement is discovered later, by a report that does not add up.
The STRICTBOOL column
'true'/'false', 't'/'f', 'yes'/'no', 'on'/'off' and '1'/'0', in any letter case. Pass them as strings; a bare number is refused. Whichever spelling goes in, true or false comes back:
Counting
Two aggregates come with the type.boolean_sum counts the true rows and boolean_avg gives the share of them:
Indexing
ASTRICTBOOL column indexes like any other:
locked flag on an account table where almost nothing is locked.
Migrating an existing column
You cannot convert aTINYINT column in place. The server refuses it:
STRICTBOOL column does not take a string expression:
5 and -1 rows meant. Everything non-zero became true above, which is what WHERE active would have said. If some report in your system used active = 1 instead, it disagreed, and now is when you find out.
Once the new column is right, drop the old one and rename:
Troubleshooting
See also
- Choosing Data Types — when a narrower column earns its place
- NULL in MySQL — what the boolean aggregates skip
- CHECK Constraints in MySQL — the other way to refuse bad values

