Three-Valued Logic
modern-sql.com
modern-sql.com
There are some interesting ramifications of these properties, including a lack of tautologies in K3 and Ł3.
'U' uninitialized
'X' strong drive, unknown logic value
'0' strong drive, logic zero
'1' strong drive, logic one
'Z' high impedance
'W' weak drive, unknown logic value
'L' weak drive, logic zero
'H' weak drive, logic one
'-' don't care
Drive levels aside, this is called tri-state in electronics: https://en.m.wikipedia.org/wiki/Three-state_logic
I wouldn't call the NULL an unknown or as a "could be anything". It's tempting to think it's the Schrodinger's Cat phenomenon, but I choose to interpret the NULL in a less sexy way: Unknown means that the state DOES NOT EXIST. It's as simple as that. Remember in relational modeling (cardinality & ordinality) the thinking is always: zero, 1 or more than 1. The NULL is simply the zero here ( which means the state does NOT exist). Interpret it as "irrelevant".
Interpreting it as either true or false (because it is unknown) is over explaining.
That's wrong.
Practical example is `1 not in (null)`
> “Every [SQL] data type includes a special value, called the null value,” “that is used to indicate the absence of any data value”.
(http://modern-sql.com/concept/null)
For the Boolean type, null = unknown:
> Note that the truth value unknown is indistinguishable from the null for the Boolean type. Otherwise, the Boolean type would have four logical values.
(http://modern-sql.com/concept/three-valued-logic)
Although they are very closely related, I believe the general `null` value (for any data type) and three-valued logic (null for Boolean) should be separated (that's why I have two articles).
It can represent both. For example, in a table of biographical data, a NULL value for DateOfDeath could represent N/A for someone still living, unknown for a dead person whose date of death is not known, and total uncertainty for a missing person who could be alive or dead.
If your table is expected to answer "how many dead people whose date of death is unknown" then you'll most certainly also need an "IsDead" (true/false) NOT NULL column. (Best separate the table into "Death" with NOT NULL DateofDeath.)
"Because it represents (and behaves) as unknown".
But I'm also inclined to think of the unknown BECAUSE of (or as a consequence of) absence of data. And most importantly, this absence of data (non-existence) is useful too.
I have a problem with the logic that intends to over fit absence/unknown to mean "it could be true or it could be false" ... or worse ... "it could be both".
If you are doing this in SQL WHERE predicates:
(T-SQL)
WHERE IsNull(IsHivPositive, 0) = 1
I would strongly argue to reimagine the use of that "boolean" column.The closest to a sensible semantics that I have seen is a 2012's paper titled "On the Logic of SQL Nulls", which argues that the "correct" interpretation of NULL is "value not existent". It is a quite theoretical paper, though, and it covers only a subset of SQL.
If you want to use NULLs meaning "value exists but is unknown" I recommend that you the papers written by Hans-Joachim Klein, mostly in the '90s. His "switching semantics" provides some very interesting rules for writing queries with NULLs, which are at least guaranteed to output a subset of the correct answers wrt some reasonable definition of "correctness" (some of his results were rediscovered recently by Libkin btw).
This is different semantics from say, taking the AND with a term that is not present, which in most conventions would have us substitute the identity value (i.e. TRUE), so that the return value is TRUE if and only if the known value is TRUE; instead, we have that the return value in SQL is NULL.
= | F | T | N
---+---+---+---
F | 1 | 0 |
---+---+---+---
T | 0 | 1 |
---+---+---+---
N | | |
Using the SELECT 1=NULL; syntax of SQLite we can see that SQLite does not even attempt to provide an answer. What would we say of something that cannot be determined? We say that it is _indeterminate_.So we can find out how NULLs behave by seeing what our database does (or reading the SQL spec.) But how we _interpret_ NULL is context and application specific. It's completely valid to interpret NULL as "data-is-missing" or "does-not-exist" if you so wish. Maybe the more reasonable interpretation is "unknown" as the article urges.
However you have urged us to regard it (not the result of its operations which is another thing) as – at one and the same time – "the state does-not-exist", "zero", "irrelevant" which is unreasonable. Treating NULLs as unknowns and the results of operations on NULLs as indeterminate is a better recommendation I think even though ultimately the interpretation is application and context specific.
In a strongly typed language with a boolean type, a comparison to null would require a type change. It's 'outside' the set of the boolean type.
Yes, if it exists (as an element of some set), then it is definitely outside the declared set of values. The main question is how we can formalize it, particularly, by defining the set NULL is a member of. For example, the following general approaches are possible:
o Extend (any or some) set of values with a special element (NULL)
o NULL = 0 (empty set)
o NULL = <> (empty tuple)
o Treat NULL as non-existence which entails having no-op if it is met, for example, 2 + NULL + 3 = 5 (just delete NULL which means skip it).
There are 19,683 possible dyadic operators for three-valued logic (3^(3^2)). I don't know if there's an equivalent minimal set of primitives from which you can construct those.
I doubt that you could define, L3's operators just with NAND (or NOR). In L3, "N implies N" is T, and "not N" is N (where N is the third truth value). So, in one case, a formula whose components are all evaluated with N has truth value T, and in the other has truth value N. This is not a proof, of course, but I'd like to see such a definition of NAND :)
Interestingly enough, with F571 SQL's propositional fragment is functionally complete: any three-valued truth table can be defined. For instance, Łukasiewicz's P ⟶ Q can be expressed with
(not P or Q) or (P is unknown and Q is unknown)
and the Słupecki operator, which is needed to obtain a functional complete system from L3, can be expressed with: (P or unknown) and unknownI don't follow. How does that bear on what minimal set of operators have to exist as givens in order to construct all the operators necessary to provide such a mapping?
I hadn't considered it before but it's amazing how fast the space of available "logic gates" blows out from just a simple transition of binary to trinary.
b) If AVG, MAX, MIN, or SUM is specified, then
Case:
i) If TXA is empty, then the result is the null value.
[1] https://stackoverflow.com/questions/12730457/why-does-sum-on...[2] http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
[?] As in, the design decision behind it. By comparison, the NULL + 10 = NULL concept seems obvious.
Now you have me wondering if, for any given database containing nulls, there is an equivalent normalized schema that represents the same information without nulls - for example, if you have a Student table with a Date of Graduation attribute that might be null, use instead an additional table of Graduated Students. It looks to me like there might be some tricky corner cases in defining 'equivalent' (you cannot query the second database for students with null graduation dates, but you can query for those without graduation dates.)
If so, then the follow-up question is whether there is a three-valued logic that always gives the same result as a particular null-free representation (my guess is yes and no, respectively.)
In other words, at the end of the day, when making a decision to deny or grant access using a bunch of these 3VL checkers, you use two rules: 1. If anyone forbid, then it's a deny. 2. If no one forbid, if running OR then you need at least one Allowed when running AND then you need to have all of them saying Allowed.
Many values in a database are approximate especially if representing real world values, but in our logic we treat them as equal even if they really aren't exactly equal, because that's practical. At least GROUP BY / aggreagates treats null equal, this was done for practicality and is a special exception which drives home the point.
In the end x == y OR (x IS NULL AND y IS NULL) simply wastes my time and adds no value to me along with the other issues that come with not simply allowing x == y checks like every normal programming language I use.
However, Value representations have their own issues, which can be seen in vulnerabilities that have occurred in non-SQL where the corresponding checks had not been performed.
In response to this is error based exceptions. Tradeoffs that we all live with.
Unfortunately it is poorly supported.
That's not a JavaScript thing, it's an IEEE 754 floating point standard thing and is the same in every programming language that implements that standard (which is basically all of them). But for some reason only JavaScript developers seem to be bothered by this.
Furthermore IEEE 754 floating point numbers don't have many properties that you'd expect from 'real' numbers. For example addition is not always associative and the distributive law does not always hold.
I'm writing javascript and I don't want to need to care about IEEE 754 floating point (all I know about is `Number` anyway).
If you compare two NaNs in C that happen to have the same binary representation, they are equal. Which means that a typical javascript runtime will need to check for that case, no? So if they have to make the decision between making all NaNs equal or unequal, and there's going to be a runtime check either way, why not make NaN == NaN and save us a headache?
For example, if you had a "person" table, the "name" column could be INAPPLICABLE if the person does not have a name, and UNKNOWN if the person's name is not known.
A lot of people make the mistake of trying to understand SQL NULL, like it's some kind of intelligent system with an underlying model behind it. It's not. It's a collection of various special-case behaviors that "make sense" in some contexts and cause confusion in many others.
SQL's null is a value. The difference is that processing null values does not cause exceptions in SQL.
In Db land you can make a column not nullable. Bit the SQL languages like PLSQL TSQL etc have the same issue.
- the results of any operations over nulls run as if the pointer were not null
- while anyhing you do in SQL with NULL would explicitly have a mapping to either a correct value or another NULL
This is all said knowing that it’s quite easy to understand why is that the case.It is known to be one of the major controversies because originally NULL means the absence of a value which entails that it is not a value. Hence, if there are no values, then we cannot do any operations. Yet, for whatever reason (avoiding exceptions etc.) expressions with NULL need to be evaluated and hence NULL is treated as a value. So we get a problem: NULL is not a value AND NULL is a value. There are different views on this problem and the solution implemented in SQL (and three-valued logic) is probably not the best one.
SQL is pretty clear what null is:
> “Every [SQL] data type includes a special value, called the null value,”[0] “that is used to indicate the absence of any data value”[1]
(http://modern-sql.com/concept/null)
[0] SQL:2011-1: §4.4.2 [1] SQL:2011-1: §3.1.1.12
A database sometimes needs to model this case: the value is unknown: maybe the paper file you digitized was corrupted or destroyed, or other valid reasons this value is not known.
Whereas null references can be avoided, like in rust etc.
Rust or functional languages show you do not generally need null references, you have options instead. It is completely different.
Null in C or C++ is much more a very costly misstake. Missing data is just reality.
Data may be incomplete, the values unknown. SQL is designed for that. It is designed to handle reality. Whereas null references are not, they cause problems you do not need...
Data != reference
you can avoid the issue of allowing invalid references everywhere
you can not avoid incomplete data.