{"id":93071,"date":"2021-12-27T17:48:13","date_gmt":"2021-12-27T17:48:13","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=93071"},"modified":"2021-12-27T17:48:13","modified_gmt":"2021-12-27T17:48:13","slug":"quantifier-predicates","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/quantifier-predicates\/","title":{"rendered":"Quantifier predicates"},"content":{"rendered":"<p>SQL is based on set theory and logic. The only bad news is that many programmers have never had a class on either of those topics. They muddle through using the Boolean operators in their programming language and think that\u2019s all there is to formal logic.<\/p>\n<p>Let\u2019s flashback to the early days of logic and play catch up. We need to start with syllogisms. Syllogisms are logical forms made up of combinations of two statements about classes of things that lead to a conclusion. They were invented by the Greeks and written up by Aristotle in <a href=\"https:\/\/en.wikipedia.org\/wiki\/Prior_Analytics\"><em>Prior Analytics<\/em><\/a>. You might have run into them, If you had a philosophy class that included lectures on formal fallacies. The three forms of statements allowed are:<\/p>\n<p>1) ALL x ARE y<\/p>\n<p>2) SOME x ARE y<\/p>\n<p>3) NO x ARE y<\/p>\n<p>These simple tools let us take two statements and come to a valid conclusion:<\/p>\n<p>All men are mortal<\/p>\n<p>All Greeks are Men<\/p>\n<p>therefore: All Greeks are mortal<\/p>\n<p>The Ancient Greeks seem to like to use a minimal set of tools which we could expect from a culture that gave us only circles and straight edges in plane geometry. We know that our logic was valid, so we are confident he will die if we know that Aristotle is a Greek. A polysyllogism, or a sorites, is a set of three or more such constructs that can be chained together to come to a conclusion.<\/p>\n<p>You can figure out syllogisms or sorites using Euler circles, Venn diagrams, or Lewis Carroll\u2019s diagrams. And before you ask, yes, it is <em>that <\/em>Lewis Carroll. People tend to forget that he was one of the pioneers in the evolution of logic. You don\u2019t hear more about him when you\u2019re studying early logic because he was on the losing side of a philosophical argument called \u201cexistential import\u201d in the literature. Briefly, this has to do with what \u201cALL x ARE y\u201d means. Does it imply that \u201cSOME x ARE y\u201d and that \u201cNO x ARE non-y\u201d; that is, there are x\u2019s in the universe. Or does it mean only that \u201cNO x ARE non-y\u201d? I will get back to this point shortly.<\/p>\n<p>George Boole and his book \u201cLaws of Thought\u201d (available in reprint additions to this very day) gave us the Boolean algebra that dominates programming languages with the basic <code>AND<\/code>, <code>OR<\/code>, and <code>NOT<\/code> operators we\u2019ve come to know and love over the decades. Our syllogisms mutated into quantifiers which could be applied to the Boolean algebra expressions. The two forms are <code>For all x, P(x),<\/code> and <code>For some x, P(x).<\/code> If you want to look up formulas in a textbook, the symbol for the universal quantifier is \u2200, an inverted letter &#8216;A&#8217;, and the symbol for the existential quantifier is \u2203, a rotated letter \u2018E\u2019.<\/p>\n<p>Existential import lost the battle, and the modern convention is that &#8220;All men are mortal&#8221; has the same meaning as &#8220;There are no men who are immortal&#8221; but does not imply that any men exist at all.<\/p>\n<p>The reasoning is that if I were to walk into a bar and announce that I can beat any pink elephant in the bar, that would be a true statement. The fact that there are no pink elephants in the bar merely shows that the problem is reduced to the minimum case. If this still seems unnatural, then consider the formal mathematical properties of these quantifiers:<\/p>\n<p>1) (\u2200x)P(x) = \u00ac(\u2203x) \u00acP(x)<\/p>\n<p>2) (\u2203x)P(x) = \u00ac(\u2200x) \u00acP(x)<\/p>\n<p>In Boolean terms, you can think of the (\u2200x) quantifier as being a generalized <code>AND<\/code> which connects an infinite string of propositions. Likewise, you can think of the (\u2203x) quantifier as a generalized <code>OR<\/code>, which connects an infinite string of propositions. These generalizations are actually taken from DeMorgan\u2019s Laws.<\/p>\n<h2>The EXISTS() predicate<\/h2>\n<p>SQL has had the <code>EXISTS()<\/code> predicate since the beginning. It\u2019s interesting within SQL because it has to return either <code>TRUE<\/code> or <code>FALSE<\/code> but can never return <code>UNKNOWN<\/code>. This is an exception to most logical operations inside SQL\u2019s three-valued logic. It\u2019s also not quite the same as the syllogisms we have been talking about.<\/p>\n<p>Consider the statement &#8220;Some salesmen are liars,&#8221; and one way we would write it with the <code>EXISTS()<\/code> predicate in SQL:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">...\r\nWHERE EXISTS (SELECT *\r\n FROM Personnel AS P, Liars AS L\r\n WHERE P.job_title = 'Salesman'\r\n AND P.emp_name = L.emp_name);<\/pre>\n<p>If we are more cynical about salesmen, we might want to formulate the predicate &#8220;All salesmen are liars&#8221; with the <code>EXISTS<\/code> predicate in SQL, using the transform rule just discussed:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">...\r\nWHERE NOT EXISTS\r\n (SELECT *\r\n FROM Personnel AS P\r\n WHERE P.job_title = 'Salesman'\r\n AND P.emp_name\r\n  NOT IN\r\n  (SELECT L.emp_name\r\n  FROM Liars AS L));<\/pre>\n<p>This informally says &#8220;There are no salesmen who are not liars&#8221; in English. In this case, the <code>IN()<\/code> predicate can be changed into a <code>JOIN<\/code>, which might improve performance and be a bit easier to read.<\/p>\n<p>As an aside, the subquery doesn\u2019t need to evaluate the <code>SELECT<\/code> clause for the <code>EXISTS()<\/code> predicate to work. In one very early version of Oracle, however, the compiler would work out the expressions in the <code>SELECT<\/code> clause and then ignore the results. Today, the preferred form is <code>SELECT *<\/code> because the star represents a nonspecific row in several places in SQL. It is easy to find in the text, and the compiler will not waste any time with expressions in the <code>SELECT <\/code>list (in fairness, this optimization should not be a problem anymore).<\/p>\n<p>Now, onto the fancy stuff!<\/p>\n<h2>The [SOME | ANY] &lt;subquery&gt; predicate<\/h2>\n<p>The predicate <code>&lt;value expression&gt; &lt;comparison op&gt; [ANY | SOME] &lt;table expression&gt;<\/code> is equivalent to taking each row of the table expression, <code>si,<\/code> (assume that they are numbered from 1 to n) of <code>&lt;table expression&gt;<\/code> and testing <code>&lt;value expression&gt; &lt;comparison op&gt; si<\/code> with <code>ORs<\/code> between the expanded expressions:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">((&lt;value expression&gt; &lt;comparison op&gt; s<sub>1<\/sub>)\r\nOR (&lt;value expression&gt; &lt;comparison op&gt; s<sub>2)<\/sub>\r\n ...\r\nOR (&lt;value expression&gt; &lt;comparison op&gt; s<sub>n<\/sub>))<\/pre>\n<p>When you get a single <code>TRUE<\/code> result, the whole predicate is <code>TRUE<\/code>. As long as <code>&lt;table expression&gt;<\/code> has cardinality greater than zero and one non-<code>NULL<\/code> value, you will get a result of <code>TRUE<\/code> or <code>FALSE<\/code>. The keyword <code>SOME<\/code> is the same as <code>ANY<\/code>, and the choice is just a matter of style and readability.<\/p>\n<p>If you think about it, the <code>IN()<\/code> predicate is equivalent to a simple <code>= ANY<\/code> predicate. In fact, that is how it is defined in the ANSI\/ISO Standard. But the <code>&lt;comparison op&gt;<\/code> can be any of <code>=, &lt;, &gt;, &lt;&gt;, &lt;=, &gt;=,<\/code> and (in theory, but not always in practice) any other comparison operator (such as <code>IS [NOT] DISTINCT FROM<\/code>).<\/p>\n<h2>The ALL &lt;subquery&gt; predicate<\/h2>\n<p>The <code>&lt;value expression&gt; &lt;comp op&gt; ALL &lt;table expression&gt;<\/code> takes each row of <code>&lt;table expression&gt;,<\/code> call them <code>s1, s2,.. sn<\/code>, builds a search condition for each such row expression, tests <code>&lt;value expression&gt; &lt;comp op&gt; si<\/code> with <code>ANDs<\/code> between the search conditions, thus:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">((&lt;value expression&gt; &lt;comp op&gt; s<sub>1<\/sub>)\r\nAND (&lt;value expression&gt; &lt;comp op&gt; s<sub>2<\/sub>)\r\n ...\r\nAND (&lt;value expression&gt; &lt;comp op&gt; s<sub>n<\/sub>))<\/pre>\n<p>When you get a single <code>FALSE<\/code> result, the whole predicate is <code>FALSE<\/code>. As long as <code>&lt;table expression&gt; <\/code>has cardinality greater than zero and all non-<code>NULL<\/code> values, you will get a result of <code>TRUE<\/code> or <code>FALSE<\/code>.<\/p>\n<p>That sounds reasonable so far. Now let <em>Empty_Table<\/em> be an empty table (no rows, cardinality zero) and <em>Null_Table<\/em> be a table with only NULLs in its rows and a cardinality greater than zero. The rules for SQL say that <code>&lt;value expression&gt; &lt;comp op&gt; ALL Null_Table<\/code> always returns <code>UNKNOWN<\/code>, and likewise <code>&lt;value expression&gt; &lt;comp op&gt; ANY Null_Table<\/code> always returns <code>UNKNOWN<\/code>. This makes sense because every row comparison test in the expansion would return <code>UNKNOWN<\/code>, so the series of <code>OR<\/code> and <code>AND<\/code> operators would behave in the usual way.<\/p>\n<p>However, <code>&lt;value expression&gt; &lt;comp op&gt; ALL Empty_Set<\/code> always returns <code>TRUE<\/code> and <code>&lt;value expression&gt; &lt;comp op&gt; ANY Empty_Set<\/code> always returns <code>FALSE<\/code>. Most people have no trouble seeing why the <code>ANY<\/code> predicate works that way; you cannot find a match, so the result is <code>FALSE<\/code>. But most people have trouble seeing why the <code>ALL<\/code> predicate is <code>TRUE<\/code>. We are trying to preserve those generalized DeMorgan\u2019s Laws.<\/p>\n<p>The <code>Foobar.x &lt;comp op&gt; ALL (SELECT y FROM Table2 WHERE &lt;search condition&gt;)<\/code> predicate converts to:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\"> ... NOT EXISTS\r\n (SELECT *\r\n FROM Foobar, Table2\r\n WHERE Foobar.x &lt;comp op&gt; Table2.y\r\n AND NOT &lt;search condition&gt;)...<\/pre>\n<p>The <code>Foobar.x &lt;comp op&gt; ANY (SELECT y FROM Table2 WHERE &lt;search condition&gt;)<\/code> predicate converts to<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\"> ... EXISTS\r\n (SELECT *\r\n FROM Foobar, Table2\r\n WHERE Foobar.x &lt;comp op&gt; Table2.y\r\n AND &lt;search condition&gt;) ...<\/pre>\n<p>Of the two quantified predicates, the <code>&lt;comp op&gt; ALL<\/code> predicate is probably the more useful of the two since it cannot be written in terms of an <code>IN()<\/code> predicate. The trick with it is to make sure that its subquery defines the set of values in which you are interested. For example, to find the authors whose books <em>all <\/em>sell for $49.95 or less, you could write:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT *\r\n FROM Authors AS A1\r\n WHERE 49.95\r\n &lt;= ALL (SELECT book_price\r\n FROM Books AS B1\r\n WHERE A1.author_name = B1.author_name);<\/pre>\n<p>The best way to think of this is to reverse the usual English sentence &#8220;Show me all x that are y&#8221; in your mind so that it says &#8220;y is the value of all x&#8221; instead.<\/p>\n<h2>The ALL predicate and Extrema functions<\/h2>\n<p>At first, it is counter-intuitive that these two predicates are <em>not<\/em> the same in SQL:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\"> x &gt;= (SELECT MAX(y) FROM Foobar)\r\n x &gt;= ALL (SELECT y FROM Foobar)<\/pre>\n<p>You have to remember the rules for the extrema functions \u2013 they drop out all the <code>NULLs<\/code> <em>before <\/em>returning the greatest, least, or computed value the aggregate function wants. But the <code>ALL<\/code> operator does not drop <code>NULLs<\/code> so that you can get them in the results. (<strong>Editor\u2019s note:<\/strong> If any <code>NULLs<\/code> are returned from the subquery, no rows are returned from the main query with <code>ALL<\/code>. While the <code>ALL<\/code> operator is not dropping <code>NULL<\/code>, <code>NULL<\/code> doesn\u2019t show up in the results because the expression <code>&gt;= NULL<\/code> will return <code>UNKNOWN<\/code>.)<\/p>\n<p>The first expression uses an aggregate function, so it returns a numeric value. In effect, it works like this:<\/p>\n<p>0) Create the data<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\"> CREATE TABLE Foobar\r\n(foo_id VARCHAR(10) NOT NULL PRIMARY KEY,\r\n y INTEGER);\r\nINSERT INTO Foobar VALUES ('Albert', 42), ('Bob', NULL), ('Chuck', 43);<\/pre>\n<p>1) We can now apply the aggregate function. Remove the rows with <code>NULLs<\/code>.<\/p>\n<p>(&#8216;Albert&#8217;, 42)<\/p>\n<p>(\u2018Chuck\u2019, 43)<\/p>\n<p>2) Find the maximum value in the column of y in the remaining rows.<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">{(42), (43)} =&gt; (43) and finally x&gt;= (43)<\/pre>\n<p>But look at the second expression. That <code>ALL()<\/code> predicate makes this a l<em>ogical expression. <\/em>Bob\u2019s <code>NULL<\/code> is not removed as it would be with an aggregation. Instead, we build a chain of <code>AND<\/code>-ed predicates:<\/p>\n<p>((&#8216;Albert&#8217;, 42)<\/p>\n<p>AND (&#8216;Bob&#8217;, NULL)<\/p>\n<p>AND (\u2018Chuck\u2019, 43))<\/p>\n<p>Which becomes in effect:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">((42 &gt;= x)\r\nAND (NULL &gt;= x) --- UNKNOWN\r\nAND (43 &gt;= x))<\/pre>\n<p>SQL\u2019s three-valued logic comes into play here. We know that<\/p>\n<p>TRUE AND UNKNOWN = UNKNOWN<\/p>\n<p>FALSE AND UNKNOWN = FALSE<\/p>\n<p>UNKNOWN AND UNKNOWN = UNKNOWN<\/p>\n<p>As you can see, once you\u2019ve got an <code>UNKNOWN<\/code> value in a chain of <code>AND<\/code>-ed predicates, you really can\u2019t get it to resolve to a <code>TRUE<\/code> value. You would have to cast them to a known value, using <code>COALESCE()<\/code> or some similar function.<\/p>\n<h2>Conclusion<\/h2>\n<p>It\u2019s always a good idea to take a little time out and learn some of the more obscure features in this very large language we call SQL. But when you do, have mercy on the poor guys that have to maintain your code after you\u2019re gone. This is what comments are for.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Predicates in SQL are often complex and difficult to understand. In this article, Joe Celko explains the logic behind a few of the predicates: EXISTS, SOME, ANY and ALL.&hellip;<\/p>\n","protected":false},"author":96214,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,143531],"tags":[5134],"coauthors":[6781],"class_list":["post-93071","post","type-post","status-publish","format-standard","hentry","category-featured","category-t-sql-programming-sql-server","tag-sql-prompt"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93071","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/96214"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=93071"}],"version-history":[{"count":3,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93071\/revisions"}],"predecessor-version":[{"id":93073,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/93071\/revisions\/93073"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=93071"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=93071"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=93071"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=93071"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}