What column type is best to use in a MySQL database for boolean values? I use boolean but my colleague uses tinyint(1).
These data types are synonyms.
I am going to take a different approach here and suggest that it is just as important for your fellow developers to understand your code as it is for the compiler/database to. Using boolean may do the same thing as using tinyint, however it has the advantage of semantically conveying what your intention is, and that's worth something.
If you use a tinyint, it's not obvious that the only values you should see are 0 and 1.
A boolean is ALWAYS true or false.
boolean isn't a distinct datatype in MySQL; it's just a synonym for tinyint. See this page in the MySQL manual.
See the quotes and examples down below from the dev.mysql.com/doc/
BOOL, BOOLEAN These types are synonyms for TINYINT(1). A value of zero
is considered false. Nonzero values are considered true:
mysql> SELECT IF(0, 'true', 'false');
+------------------------+
| IF(0, 'true', 'false') |
+------------------------+
| false |
+------------------------+
mysql> SELECT IF(1, 'true', 'false');
+------------------------+
| IF(1, 'true', 'false') |
+------------------------+
| true |
+------------------------+
mysql> SELECT IF(2, 'true', 'false');
+------------------------+
| IF(2, 'true', 'false') |
+------------------------+
| true |
+------------------------+
However, the values TRUE and FALSE are merely aliases for 1 and 0, respectively, as shown here:
mysql> SELECT IF(0 = FALSE, 'true', 'false');
+--------------------------------+
| IF(0 = FALSE, 'true', 'false') |
+--------------------------------+
| true |
+--------------------------------+
mysql> SELECT IF(1 = TRUE, 'true', 'false');
+-------------------------------+
| IF(1 = TRUE, 'true', 'false') |
+-------------------------------+
| true |
+-------------------------------+
mysql> SELECT IF(2 = TRUE, 'true', 'false');
+-------------------------------+
| IF(2 = TRUE, 'true', 'false') |
+-------------------------------+
| false |
+-------------------------------+
mysql> SELECT IF(2 = FALSE, 'true', 'false');
+--------------------------------+
| IF(2 = FALSE, 'true', 'false') |
+--------------------------------+
| false |
+--------------------------------+
The last two statements display the results shown because 2 is equal
to neither 1 nor 0.
Personally I would suggest use tinyint as a preference, because boolean doesn't do what you think it does from the name, so it makes for potentially misleading code. But at a practical level, it really doesn't matter -- they both do the same thing, so you're not gaining or losing anything by using either.
use enum its the easy and fastest
i will not recommend enum or tinyint(1) as bit(1) needs only 1 bit for storing boolean value while tinyint(1) needs 8 bits.
ref
TINYINT vs ENUM(0, 1) for boolean values in MySQL
While it's true that bool and tinyint(1) are functionally identical, bool should be the preferred option because it carries the semantic meaning of what you're trying to do. Also, many ORMs will convert bool into your programing language's native boolean type.
My experience when using Dapper to connect to MySQL is that it does matter. I changed a non nullable bit(1) to a nullable tinyint(1) by using the following script:
ALTER TABLE TableName MODIFY Setting BOOLEAN null;
Then Dapper started throwing Exceptions. I tried to look at the difference before and after the script. And noticed the bit(1) had changed to tinyint(1).
I then ran:
ALTER TABLE TableName CHANGE COLUMN Setting Setting BIT(1) NULL DEFAULT NULL;
Which solved the problem.
Whenever you choose int or bool it matters especially when nullable column comes into play.
Imagine a product with multiple photos. How do you know which photo serves as a product cover? Well, we would use a column that indicates it.
So far out product_image table has two columns: product_id and is_cover
Cool? Not yet. Since the product can have only one cover we need to add a unique index on these two columns.
But wait, if these two column will get an unique index how would you store many non-cover images for the same product? The unique index would throw an error here.
So you may though "Okay, but you can use NULL value since these are ommited by unique index checks", and yes this is truth, but we are loosing linguistic rules here.
What is the purpose of NULL value in boolean type column? Is it "all", "any", or "no"? The null value in boolean column allows us to use the unique index, but it also messes up how we interpret the records.
I would tell that in some cases the integer can serve a better purpose since its not bound to strict true or false meaning
Related
Is there a way in sql to, by default bring back values regardless of if they are true or false?
for example I have a column, 'Mandatory' which datatype is a bit.
Is there a way to bring back records where the column 'Mandatory' is either true or false or null?
something like
Select * From Table Where Mandatory = .... etc
select * from Table
where mandatory is null or mandatory in (0,1)
If the mandatory is a bit, this code is definitely true. There is no other possibility.
Let me assume you are using SQL Server -- because it supports bit but not boolean.
You can use:
where mandatory = 1
or
where mandatory = 'true'
resolved by doing this
ISNULL(Mandatory,0) =
CASE
WHEN #Mandatory = 0 THEN 0
WHEN #Mandatory = 1 THEN 1
WHEN #Mandatory = 2 THEN ISNULL(Mandatory,0)
essentially saying that when 2 is inputted, it will bring back all values for true, false and null. works very well
The question is how to run a binary logic into trinary logic.
Binary = There are distinct, actual values: in regards to this question the values [True] or [False]
Trinary = There are distinct, actual values plus unknown values: in regards to this question the values [ True | False | NULL ]
It is not possible to include unknown values in a single WHERE condition. Instead it has to be checked separately:
WHERE mandatory IN (0, 1) -- check whether TRUE or FALSE against bit
OR mandatory IS NULL -- also include UNKNOWN
This approach is better than using a function as a function in a WHERE condition can (and will) lead more often than not to performance losses.
I've read a few articles like this one about a license plate value of NULL (about Droogie from DEF CON 27), including part of chapter three Little Data in the book Humble Pi by Matt Parker (talking about Steve Null), where storing a string value of "NULL" in a database matches NULL values.
With databases I've used (at least AFAIK), "NULL" isn't the same as a NULL value. The state of a field being NULL is stored separately from the value.
So SQL like
SELECT bar
FROM foo
WHERE foobar IS NULL;
would be different than
SELECT bar
FROM foo
WHERE foobar = 'NULL';
When I first heard these stories I thought they must be urban legends, but after seeing a few more it made me wonder if I was missing something? Is it a matter of some databases that don't distinguish "NULL" from is NULL (if so, which ones, any current ones)? Or is it a matter of whoever built the database application storing "NULL" as a string for NULL values or some other poor design?
Further reading:
BBC on Jennifer Null
Mashable on Droogie's DEF CON Talk
Matt Parker on Steve Null
Passing NULL as a surname in SOAP
Droogie's Go NULL Yourself talk from Def Con 27
Droogie finally got his plate renewed
To summarize my question:
Do some databases mishandle NULL vs. "NULL" ?
Is that only historical databases, or are there current databases that do the same?
Is there a logical reason to have "NULL" equal IS NULL from architecture POV?
Or are all of these an example of an application design failure?
How can you mess it up that bad?
I'd really love to see an example of some SQL that confuses NULL and 'NULL'.
You are describing two different concepts:
In relational databases 'null' is a CHAR value (of length 4), as simple as that.
On the other side null is not a value, but represents a "missing value". It's not the absence of value either; it means that "the value does exist, but we failed to recover it."
Therefore, they are both very different concepts. I don't know a database that mishandles nulls as you present it. However, I can think of applications that do not distinguish them well. I would consider that defects on the app, not on the database engines themselves.
Anyway, here are a few SQL expressions in PostgreSQL and their values to illustrate the definitions above:
select
'null' = 'null', -- 1. TRUE
'null' = null, -- 2. null (actually UNKNOWN)
'null' <> null, -- 3. null (actually UNKNOWN)
'null' is null, -- 4. FALSE
'null' is not null, -- 5. TRUE
null is null, -- 6. TRUE
null is not null, -- 7. FALSE
null = null, -- 8. null (actually UNKNOWN)
null <> null, -- 9. null (actually UNKNOWN)
null is not distinct from null, -- 10. TRUE
(null = null) is unknown, -- 11. TRUE
(null = null) is true, -- 12. FALSE
(null = null) is false, -- 13. FALSE
(null <> null) is unknown -- 14. TRUE
See running example at DB Fiddle.
Note. When you typically compare against null the result is the bona fide value UNKNOWN, not TRUE, not FALSE. However, most database drivers convert that value to a null when sending it to your app, as you can see in the cases #2, #3, #8, and #9 above.
It's a design flaw. "NULL" is a string and you shouldn't have to use a string to represent Nothing. So in 1 case, you're looking for a populated value of exactly "NULL" where with IS NULL there actually is nothing there.
Context
I just met a single table in a PostgreSQL database which is actually only defining a triplet of coded values that are used across the whole database as a ternary data type. I am a bit astonished at first glance, I feel it's weird; there should be some ternary data type?
I've searched the web, especially the PostgreSQL documentation without any apparent success (I'm probably wrong with my search keywords?!), but maybe there is no other solution.
Question
I would like to know if it exists a ternary (as comparison with binary or boolean) data type in PostgreSQL or more generally in SQL which permits to express a "ternary state" (or "ternary boolean" which is clearly is an abuse of language), which I would represent as a general idea as:
+-------+----------+--------------------+
| id | type | also expressed as |
+-------+----------+--------------------+
| 0 | false | 0 |
| 1 | true | 1 |
| 2 | unknown | 2 |
+-------+----------+--------------------+
where unknown can be whatever third state you are actually dealing with.
I would like to know if it exists a ternary (as comparison with binary or boolean) data type
Actually, the boolean data type is ternary because it can have the values true, false and null.
Consider this table:
create table data (some_number int, some_flag boolean);
And the following data:
insert into data (some_number, some_flag)
values (1, true), (2, false), (3, null);
Then the following:
select *
from data
where some_flag = false;
will only return one row (with some_number = 2)
there is not a specific ternary operator but you could use case
select case when operator =0 then 'false'
when operatore =1 then 'true'
when operator = 2 then 'unknow'
else 'not managed'
end
from your_table
I second a_horse_with_no_name's solution for your specific example, but the more general approach is to use an enum data type:
CREATE TYPE ternary AS ENUM (
'never',
'sometimes',
'always'
);
Constants of such a data type are written as string constantls, e.g. 'never', but the internal storage uses 4 bytes per value, regardless of the length of the label.
I've been looking to find a good way to do a SQL query where I can have a where statement which, if left blank, will act like it wasn't there at all. I've found this, which seems to work quite well:
WHERE (Column = #value OR #value is null)
If I specify a value for #value, the search is filtered like I want. But if I pass in null, it's like saying #value can be anything. I like this. This is good. What I don't understand though is, why does this work like this?
If #value is null, your WHERE clause:
WHERE (Column = #value OR #value is null)
reduces to
WHERE (Column = #value OR 1=1)
(This is similar to if (Column == value || true) in other common languages)
An OR conjunction is true if either of its operands (sides) are true: SQL uses three valued logic
+---------+------+---------+---------+
| A OR B | TRUE | Unknown | FALSE |
+---------+------+---------+---------+
| TRUE | TRUE | TRUE | TRUE |
| Unknown | TRUE | Unknown | Unknown |
| FALSE | TRUE | Unknown | FALSE |
+---------+------+---------+---------+
And so:
If #value is null, the right side of your WHERE clause is true, so the entire conditional is true, and your WHERE clause will always be satisfied.
If #value isn't null, then the right side of your WHERE clause is false, then whether the WHERE clause is satisfied depends on whether Column = #value.
Well, there are two cases:
1) #value is "something".
In this case, the second clause is always false, because "something" is never null. So all that effectively remains is WHERE Column = #value.
2) #value is null
In this case, the second clause is always false, because null never equals anything. So all that effectively remains is WHERE #value is null and #value is known to be null, so this is like WHERE 1 = 1 and the whole WHERE is ignored. The database should be clever enough to figure this out before touching any data, so this should perform just like if there was no condition specified at all.
So what you have here, is a single SQL statement that can act like two, with an "optional WHERE". The advantage over two separate SQL statements for the two cases is that you don't need conditional logic in your application when building the SQL statement (which can get really hairy if there are more than one of these "toggles").
In SQL , why does 10/NULL evaluate to NULL (or unknown) ? Example :
if((10/NULL) is NULL)
DBMS_OUTPUT.PUT_LINE("Null.");
However , 1 = NULL being a COMPARISON is considered as FALSE. Shouldn't 10/NULL also be considered as FALSE ?
I am referring to SQL only . Not any DBMS in particular. And it might be a duplicate but I didn't know what keywords to put in search for this query.
Shouldn't 10/NULL also be considered as FALSE?
No, because:
Any arithmetic expression containing a null always evaluates to null. For example, null added to 10 is null. In fact, all operators (except concatenation) return null when given a null operand.
Emphasis mine, taken from the Oracle manual: http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements005.htm#i59110
And this is required by the SQL standard.
Edit, as the question was for RDBMS in general:
SQL Server
When SET ANSI_NULLS is ON, an operator that has one or two NULL expressions returns UNKNOWN
Link to the the manual:
MySQL
An expression that contains NULL always produces a NULL value unless otherwise indicated in the documentation for a particular function or operator
Link to the manual
DB2
if either operand can be null, the result can be null, and if either is null, the result is the null value
Link to the manual:
PostgreSQL
Unfortunately I could not find such an explicit statement in the PostgreSQL manual, although I sure it behaves the same.
Warning: The "(except concatenation)" is an Oracle only and non-standard exception. (The empty string and NULL are almost identical in Oracle). Concatenating nulls gives null in all other DBMS.
1 = null is not null. It is actually unknown. As well as any other null operation.
The equality predicate 1 = NULL evaluates to NULL. But NULL in a boolean comparison is considered false.
If you do something like NOT( 1 = NULL ), 1 = NULL evaluates to NULL, NOT( NULL ) evaluates to NULL and so the condition as a whole ends up evaluating to false.
Oracle has a section in their documentation on handling NULL values in comparisons and conditional statements-- other databases will handle things in an very similar manner.
10/something means that you are counting how much "something" will be in 10
in this case you're counting how much "nothing" will be in 10 - that's infinity, unknown..
1 = NULL is false because one does not equal nothing
The NULLIF function accepts two parameters. If the first parameter is equal to the second parameter, NULLIF returns Null. Otherwise, the value of the first parameter is returned.
NULLIF(value1, value2)
NVL
The NVL function accepts two parameters. It returns the first non-NULL parameter or NULL if all parameters are NULL.
also check this conditional outcomes:
This "null equals UNKNOWN truth value" proposition introduces an inconsistency into SQL 3VL. One major problem is that it contradicts a basic property of nulls, the property of propagation. Nulls, by definition, propagate through all SQL expressions. The Boolean truth values do not have this property. Consider the following scenarios in SQL:1999, in which two Boolean truth values are combined into a compound predicate. According to the rules of SQL 3VL, and as shown in the 3VL truth table shown earlier in this article, the following statements hold:
( TRUE OR UNKNOWN ) → TRUE
( FALSE AND UNKNOWN ) → FALSE
However, because nulls propagate, treating null as UNKNOWN results in the following logical inconsistencies in SQL 3VL:
( TRUE OR NULL ) → NULL ( = UNKNOWN )
( FALSE AND NULL ) → NULL ( = UNKNOWN )
The SQL:1999 standard does not define how to deal with this inconsistency, and results could vary between implementations. Because of these inconsistencies and lack of support from vendors the SQL Boolean datatype did not gain widespread acceptance. Most SQL DBMS platforms now offer their own platform-specific recommendations for storing Boolean-type data.
Note that in the PostgreSQL implementation of SQL, the null value is used to represent all UNKNOWN results and the following evaluations occur:
( TRUE OR NULL ) → TRUE
( FALSE AND NULL ) → FALSE
( FALSE OR NULL ) IS NULL → TRUE
( TRUE AND NULL ) IS NULL → TRUE