<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Experimental Thoughts &#187; Logic</title>
	<atom:link href="http://thoughts.j-davis.com/category/logic/feed/" rel="self" type="application/rss+xml" />
	<link>http://thoughts.j-davis.com</link>
	<description>Ideas on Databases, Logic, and Language by Jeff Davis</description>
	<lastBuildDate>Thu, 06 May 2010 19:29:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Temporal PostgreSQL Roadmap</title>
		<link>http://thoughts.j-davis.com/2010/03/09/temporal-postgresql-roadmap/</link>
		<comments>http://thoughts.j-davis.com/2010/03/09/temporal-postgresql-roadmap/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 04:49:06 +0000</pubDate>
		<dc:creator>Jeff Davis</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Language]]></category>
		<category><![CDATA[Logic]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Temporal]]></category>

		<guid isPermaLink="false">http://thoughts.j-davis.com/?p=254</guid>
		<description><![CDATA[Why are temporal extensions in PostgreSQL important? Quite simply, managing time data is one of the most common requirements, and current general-purpose database systems don&#8217;t provide us with the basic tools to do it. Every general-purpose DBMS falls short both in terms of usability and performance when trying to manage temporal data. What is already [...]]]></description>
			<content:encoded><![CDATA[<p>Why are temporal extensions in PostgreSQL important? Quite simply, managing time data is one of the most common requirements, and current general-purpose database systems don&#8217;t provide us with the basic tools to do it. Every general-purpose DBMS falls short both in terms of usability and performance when trying to manage temporal data.</p>
<p>What is already done?</p>
<p><span id="more-254"></span></p>
<ul>
<li><a href="http://pgfoundry.org/projects/temporal">PERIOD data type</a>, which can represent anchored intervals of time; that is, a chunk of time with a definite beginning and a definite end (in contrast to a SQL INTERVAL, which is not anchored to any specific beginning or end time).
<ul>
<li>Critical for usability because it acts as a <em>set</em> of time, so you can easily test for containment and other operations without using awkward constructs like BETWEEN or lots of comparisons (and keeping track of inclusivity/exclusivity of boundary points).</li>
<li>Critical for performance because you can index the values for efficient &#8220;contains&#8221; and &#8220;overlaps&#8221; queries (among others).</li>
</ul>
</li>
</ul>
<ul>
<li>Temporal Keys (called Exclusion Constraints, and will be available in the next release of PostgreSQL, 9.0), which can enforce the constraint that no two periods of time (usually for a given resource, like a person) overlap. See the <a href="http://developer.postgresql.org/pgdocs/postgres/sql-createtable.html">documentation</a> (look for the word &#8220;EXCLUDE&#8221;), and see my previous articles (<a href="../2009/11/01/temporal-keys-part-1/">part 1</a> and <a href="../2009/11/08/temporal-keys-part-2/">part 2</a>) on the subject.
<ul>
<li>Critical for usability to avoid procedural, error-prone hacks to enforce the constraint with triggers or by splitting time into big chunks.</li>
<li>Critical for performance because it performs comparably to a UNIQUE index, unlike the other procedural hacks which are generally too slow to use for most real systems.</li>
</ul>
</li>
</ul>
<p>What needs to be done?</p>
<ul>
<li>Range Types &#8212; Aside from PERIOD, which is based on TIMESTAMPTZ, it would also be useful to have very similar types based on, for example, DATE. It doesn&#8217;t stop there, so the natural conclusion is to generalize PERIOD into &#8220;range types&#8221; which could be based on almost any subtype.</li>
<li>Range Keys, Foreign Range Keys &#8212; If Range Types are known to the Postgres engine, that means that we can have syntactic sugar for range keys (like temporal keys, except for any range type), etc., that would internally use Exclusion Constraints.</li>
<li>Range Join &#8212; If Range Types are known to the Postgres engine, there could be syntactic sugar for a &#8220;range join,&#8221; that is, a join based on &#8220;overlaps&#8221; rather than &#8220;equals&#8221;. More importantly, there could be a new join type, a Range Merge Join, that could perform this join efficiently (without a Range Merge Join, a range join would always be a nested loop join).</li>
<li>Simple table logs &#8212; The ability to easily create an effective &#8220;audit log&#8221; or similar trigger-based table log, that can record changes and be efficiently queried for historical state or state changes.</li>
</ul>
<p>I&#8217;ll be speaking on this subject (specifically, the new Exclusion Constraints feature) in the upcoming <a href="http://postgresqlconference.org">PostgreSQL Conference EAST 2010</a> (my <a href="http://postgresqlconference.org/2010/east/talks/not_just_unique_exclusion_constraints">talk description</a>) in Philadelphia later this month and <a href="http://pgcon.org">PGCon 2010</a> (my <a href="http://www.pgcon.org/2010/schedule/events/201.en.html">talk description</a>) in Ottawa this May. In the past, these conferences and others have been a great place to get ideas and help me move the temporal features forward.</p>
<p>The existing features have been picking up a little steam lately. The <a href="http://lists.pgfoundry.org/pipermail/temporal-general/">temporal-general mailing list</a> has some traffic now &#8212; fairly low, but enough that others contribute to the discussions, which is a great start. I&#8217;ve also received some great feedback from a number of people, including the folks at <a href="http://pgexperts.com">PGX</a>. There&#8217;s still a ways to go before we have all the features we want, but progress is being made.</p>
]]></content:encoded>
			<wfw:commentRss>http://thoughts.j-davis.com/2010/03/09/temporal-postgresql-roadmap/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Scalability and the Relational Model</title>
		<link>http://thoughts.j-davis.com/2010/03/07/scalability-and-the-relational-model/</link>
		<comments>http://thoughts.j-davis.com/2010/03/07/scalability-and-the-relational-model/#comments</comments>
		<pubDate>Sun, 07 Mar 2010 21:37:24 +0000</pubDate>
		<dc:creator>Jeff Davis</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Language]]></category>
		<category><![CDATA[Logic]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://thoughts.j-davis.com/?p=242</guid>
		<description><![CDATA[The relational model is just a way to represent reality. It happens to have some very useful properties, such as closure over many useful operations &#8212; but it&#8217;s a purely logical model of reality. You can implement relational operations using hash joins, MapReduce, or pen and paper. So, right away, it&#8217;s meaningless to talk about [...]]]></description>
			<content:encoded><![CDATA[<p>The relational model is just a way to represent reality. It happens to have some very useful properties, such as closure over many useful operations &#8212; but it&#8217;s a purely logical model of reality. You can implement relational operations using hash joins, MapReduce, or pen and paper.</p>
<p>So, right away, it&#8217;s meaningless to talk about the scalability of the relational model. Given a particular question, it might be difficult to break it down into bite-sized pieces and distribute it to N worker nodes. But going with MapReduce doesn&#8217;t solve that scalability problem &#8212; it just means that you will have a hard time defining a useful map or reduce operation, or you will have to change the question into something easier to answer.</p>
<p><span id="more-242"></span>There may exist scalability problems in:</p>
<ul>
<li>SQL, which defines requirements outside the scope of the relational model, such as ACID properties and transactional semantics.</li>
<li>Traditional architectures and implementations of SQL, such as the &#8220;table is a file&#8221; equivalence, lack of sophisticated types, etc.</li>
<li>Particular implementations of SQL &#8212; e.g. &#8220;MySQL can&#8217;t do it, so the relational model doesn&#8217;t scale&#8221;.</li>
</ul>
<p>Why are these distinctions important? As with many debates, <a title="Terminology Confusion" href="http://thoughts.j-davis.com/2007/12/11/terminology-confusion/">terminology confusion</a> is at the core, and prevents us from dealing with the problems directly. If SQL is defined in a way that causes scalability problems, we need to identify precisely those requirements that cause a problem, so that we can proceed forward without losing all that has been gained. If the traditional architectures are not suitable for some important use-cases, they need to be adapted. If some particular implementations are not suitable, developers need to switch or demand that it be made competitive.</p>
<p>The NoSQL movement (or at least the hype surrounding it) is far too disorganized to make real progress. Usually, incremental progress is best; and sometimes a fresh start is best, after drawing on years of lessons learned. But it&#8217;s never a good idea to start over with complete disregard for the past. For instance, an <a href="http://about.digg.com/blog/looking-future-cassandra">article from Digg</a> starts off great:</p>
<blockquote><p>The fundamental problem is endemic to the relational database mindset, which places the burden of computation on reads rather than writes.</p></blockquote>
<p>That&#8217;s good because he blames it on the <em>mindset</em> not the <em>model</em>,<em> </em>and then identifies a specific problem. But then the article completely falls flat:</p>
<blockquote><p>Computing the intersection with a JOIN is much too slow in MySQL, so we have to do it in PHP.</p></blockquote>
<p>A join is faster in PHP than MySQL? Why bother even discussing SQL versus NoSQL if your particular implementation of SQL &#8212; MySQL &#8212; can&#8217;t even do a hash join, the exact operation that you need? Particularly when almost every other implementation can (including PostgreSQL)? That kind of reasoning won&#8217;t lead to solutions.</p>
<p>So, where do we go from here?</p>
<ol>
<li>Separate the SQL model from the other requirements (some of which may limit scalability) when discussing improvements.</li>
<li>Improve the SQL model (my readers know that I&#8217;ve criticized SQL&#8217;s logical problems many times in the past).</li>
<li>Improve the implementations of SQL, particularly how tables are physically stored.</li>
<li>If you&#8217;re particularly ambitious, come up with a relational alternative to SQL that takes into account what&#8217;s been learned after decades of SQL and can become the next general-purpose DBMS language.</li>
</ol>
<p>EDIT 2010-03-09: I should have cited Josh Berkus&#8217;s talk on <a href="http://www.pgexperts.com/document.html?id=40">Relational vs. Non-Relational</a> (complete list of <a href="http://www.pgexperts.com/presentations.html">PGX talks</a>), which was part of the inspiration for this post.<a href="http://www.pgexperts.com/document.html?id=40"><br />
</a></p>
]]></content:encoded>
			<wfw:commentRss>http://thoughts.j-davis.com/2010/03/07/scalability-and-the-relational-model/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Temporal Keys, Part 1</title>
		<link>http://thoughts.j-davis.com/2009/11/01/temporal-keys-part-1/</link>
		<comments>http://thoughts.j-davis.com/2009/11/01/temporal-keys-part-1/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 00:55:34 +0000</pubDate>
		<dc:creator>Jeff Davis</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Logic]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Temporal]]></category>

		<guid isPermaLink="false">http://thoughts.j-davis.com/?p=171</guid>
		<description><![CDATA[&#8220;Schedule conflict&#8221; &#8212; it&#8217;s one of the simplest and most common constraints for business or any other organization. One person cannot be in two places at the same time; and in many cases a only a single person can use a given resource at any time. Does your database system know anything about a schedule [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;Schedule conflict&#8221; &#8212; it&#8217;s one of the simplest and most common constraints for business or any other organization. One person cannot be in two places at the same time; and in many cases a only a single person can use a given resource at any time.</p>
<p>Does your database system know anything about a schedule conflict? Should it?</p>
<p>Constraints are always enforced at some point, it&#8217;s just a matter of when, how, and the cost of correcting the situation.</p>
<p><span id="more-171"></span>Consider two professors who try to reserve the same lecture hall at overlapping times (let&#8217;s say 1-2pm, and 1:30-2:30pm). Now imagine two possible resolutions:</p>
<ol>
<li>They are blissfully unaware of the schedule conflict until they have already promoted their lecture, attracted an audience, and arrived at the building. The professor scheduled for 1:30-2:30pm will be disappointed to find it already in use, and the students will be confused. The second lecture may have to be canceled due to the confusion, or lose a substantial number of attendees.</li>
<li>At the time of scheduling, one professor is given an error message to the effect of &#8220;this room is already reserved, please choose a different time&#8221;.</li>
</ol>
<p>Observe that neither one really solves the problem: the second resolution still forces one professor to choose a less-desirable time. However, it is a <em>much</em> cheaper resolution. As with many problems, early detection is simplest and cheapest to resolve.</p>
<p>Of course, there are many resolutions that fall between the first and the second. For instance, you might run a program every hour that checks for conflicts and alerts the parties involved. That may work, but there are still problems:</p>
<ul>
<li>You&#8217;ve now introduced uncertainty into the system: do I have a reservation or not? If there is a conflict later, will I be kicked out or will they?</li>
<li>You have to come up with rules for resolution: does the first one win? How do you define &#8220;first&#8221; if transactions are running for a while? What if someone makes a reservation &#8220;first&#8221; but then makes all kinds of changes later; were they really first or did they just game the system?</li>
<li>If someone&#8217;s reservation gets bumped, you have to now have a new strange state for a reservation, in which it is disabled, the organizer has (hopefully) been notified, and it needs to change.</li>
<li>Notice that everything is very procedural and specific to the business. You have to have a notification mechanism, and rules for how to resolve it.</li>
<li>Let&#8217;s go back to the definition of &#8220;first&#8221;: say you have made a reservation, and you get bumped by the conflict detector. In between the time you made the reservation and the time you were notified of a conflict, someone else reserved your second choice. Are you now first in line for that time slot? If so, that has a cascading effect such that it&#8217;s almost impossible for the person that took the second-choice slot to know that they are at risk of being bumped.</li>
</ul>
<p>These thought experiments might seem like edge cases, but reservation systems have two common traits that make these problems very real:</p>
<ol>
<li>They tend to start allowing reservations of a specific resource at a specific time, published in advance.</li>
<li>There tend to be some resources and time slots that have a much higher value than the others.</li>
</ol>
<p>These two traits lead to heavy contention.</p>
<p>Now, how would you go about enforcing such a constraint (non-overlapping time periods) in the database? While considering possible solutions, think about:</p>
<ul>
<li>Does the solution work for a wide variety of use cases, or only in special cases?</li>
<li>How well would it perform, under low contention and high contention, and under varied workloads?</li>
<li>Can it be implemented in a general purpose RDBMS, like PostgreSQL?</li>
<li>Is it procedural in nature, or declarative?</li>
</ul>
<p>I think it&#8217;s worthwhile to consider the problem, so I will end this article now, and provide some approaches, as well as my real answer, in the next article. In the meantime, feel free to post ideas as comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://thoughts.j-davis.com/2009/11/01/temporal-keys-part-1/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>What is the deal with NULLs?</title>
		<link>http://thoughts.j-davis.com/2009/08/02/what-is-the-deal-with-nulls/</link>
		<comments>http://thoughts.j-davis.com/2009/08/02/what-is-the-deal-with-nulls/#comments</comments>
		<pubDate>Sun, 02 Aug 2009 22:40:23 +0000</pubDate>
		<dc:creator>Jeff Davis</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Language]]></category>
		<category><![CDATA[Logic]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://davisjeff.wordpress.com/?p=4</guid>
		<description><![CDATA[A recent thread on pgsql-hackers warrants some more extensive discussion. In the past, I&#8217;ve criticized NULL semantics, but in this post I&#8217;d just like to explain some corner cases that I think you&#8217;ll find interesting, and try to straighten out some myths and misconceptions. First off, I&#8217;m strictly discussing SQL NULL here. SQL NULL is [...]]]></description>
			<content:encoded><![CDATA[<p>A recent <a title="recent thread on pgsql-hackers" href="http://archives.postgresql.org/pgsql-hackers/2009-07/msg01518.php">thread on pgsql-hackers</a> warrants some more extensive discussion. In the past, I&#8217;ve criticized NULL semantics, but in this post I&#8217;d just like to explain some corner cases that I think you&#8217;ll find interesting, and try to straighten out some myths and misconceptions.</p>
<p>First off, I&#8217;m strictly discussing SQL NULL here. SQL NULL is peculiar in a number of ways, and the general excuse for this is that there is a need to represent &#8220;missing information&#8221; &#8212; which may be true. But there are lots of ways to represent missing information, as I pointed out <a title="None, nil, Nothing, undef, NA, and SQL NULL" href="http://thoughts.j-davis.com/2008/08/13/none-nil-nothing-undef-na-and-sql-null/">in a previous post</a>, and SQL&#8217;s approach to missing information is, well, &#8220;unique&#8221;.</p>
<p><span id="more-4"></span></p>
<ul>
<li>&#8220;NULL is not a value&#8221; &#8212; If you hear this one, beware: it&#8217;s in direct contradiction to the SQL standard, which uses the phrase &#8220;null value&#8221; dozens of times. It&#8217;s hard to imagine that NULL is not any kind of value at all; because it&#8217;s routinely passed to functions and operators, predicates can evaluate to NULL, and SQL uses a kind of three-<strong>valued</strong> logic (3VL) in some contexts. The phrase &#8220;NULL is not a value&#8221; also raises the question: &#8220;what is it, then?&#8221;.</li>
<li>NULL means &#8220;unknown&#8221; (i.e. the third truth value) &#8212; This doesn&#8217;t hold up either. SUM of no tuples returns NULL, but clearly the SUM of no tuples is not unknown! SQL will happily generate NULLs from aggregates or outer joins without any NULLs at all in the database. Do you not know something you did know before, or do you now know that you don&#8217;t know something that you didn&#8217;t know you didn&#8217;t know before? Also, if NULL means &#8220;unknown&#8221;, how do you differentiate a boolean field for which you do not know the value, and a boolean field for which you do know the value, and it happens to be &#8220;unknown&#8221; (perhaps this is why boolean columns are a PostgreSQL extension and not part of the core SQL standard)?</li>
<li>&#8220;NULL is false-like&#8221; &#8212; Don&#8217;t think of NULL as false-like, or &#8220;more false than true&#8221;. It&#8217;s a tempting rule of thumb, but it&#8217;s misleading. For instance, in a WHERE clause, a NULL predicate is treated like FALSE. However, in a constraint (like a <code>CHECK</code> constraint), NULL is treated like TRUE. Perhaps most importantly, when in a 3VL context (like a boolean expression), this misconception leads to problems when you try to invert the logic, e.g., use <code>NOT</code>.</li>
<li>&#8220;Oh, that makes sense&#8221; &#8212; When you see individual behaviors of NULL, they look systematic, and your brain quickly sees a pattern and extrapolates what might happen in other situations. Often, that extrapolation is wrong, because NULL semantics are a mix of behaviors. I think the best way to think about NULL is as a Frankenstein monster of several philosophies and systems stitched together by a series of special cases.</li>
<li><code>p OR NOT p</code> &#8212; Everyone should know that this is not always true in SQL. But most people tend to reason assuming that this is always true, so you have to be very careful, and work against your intuition very deliberately, in order to form a correct SQL query.</li>
<li>SUM() versus + (addition) &#8212; SUM is not repeated addition. SUM of <code>1</code> and <code>NULL</code> is <code>1</code>, but <code>1 + NULL</code> is NULL.</li>
<li>Aggregates ignore NULLs &#8212; According to the standard, aggregates are supposed to ignore NULLs, because the information is missing. But why is it OK to ignore the missing information in an aggregate, but not, say, with the + operator? Is it really OK to just ignore it?</li>
<li>Aggregates return NULL &#8212; According to the standard, aggregates are supposed to return NULL when they have no non-NULL input. Just because you don&#8217;t have any input tuples, does that really mean that the result is undefined, missing, or unknown? It&#8217;s certainly not unknown! What about SUM over zero tuples, wouldn&#8217;t the most useful result be zero?</li>
<li>SQL breaks its own rules &#8212; The aforementioned aggregate rules don&#8217;t work very well for <code>COUNT()</code>, the simplest of all aggregates. So, they have two versions of count: <code>COUNT(*)</code> breaks the &#8220;aggregates ignore nulls&#8221; rule and the &#8220;aggregates return null&#8221; rule, and COUNT(x) only breaks the latter. But wait! There&#8217;s more: <code>ARRAY_AGG()</code> breaks the former but not the latter. But no exception is made for SUM &#8212; it still returns NULL when there are no input tuples.</li>
<li>NULLs appear even when you have complete information &#8212; Because of OUTER JOIN and aggregates, NULLs can appear even when you don&#8217;t have any NULLs in your database! As a thought experiment, try to reconcile this fact with the various &#8220;definitions&#8221; of NULL.</li>
<li><code>WHERE NOT IN (SELECT ...)</code> &#8212; This one gets everyone at one point or another. If the subselect produces any NULLs, then NOT IN can only evaluate to FALSE or NULL, meaning you get no tuples. Because it&#8217;s in a WHERE clause, it will return no results. You are less likely to have a bunch of NULLs in your data while testing, so chances are everything will work great until you get into production.</li>
<li><code>x &gt;= 10 or x &lt;= 10</code> &#8212; Not a tautology in SQL.</li>
<li><code>x IS NULL AND x IS DISTINCT FROM NULL</code> &#8212; You probably don&#8217;t know this, but this expression can evaluate to TRUE! That is, if x = ROW(NULL).</li>
<li><code>NOT x IS NULL</code> is not the same as <code>x IS NOT NULL</code> &#8212; If <code>x</code> is <code>ROW(1,NULL)</code>, then the former will evaluate to TRUE, and the latter will evaluate to FALSE. Enjoy.</li>
<li><code>NOT x IS NULL AND NOT x IS NOT NULL</code> &#8212; Want to know if you have a value like <code>ROW(1, NULL)</code>? To distinguish it from NULL and also from values like <code>ROW(1,1)</code> and <code>ROW(NULL,NULL)</code>, this expression might help you.</li>
<li>NULLs can exist inside some things, but not others &#8212; If you concatenate: <code>firstname || mi || lastname</code>, and &#8220;mi&#8221; happens to be null, the entire result will be null. So strings cannot contain a NULL, but as we see above, a record can.</li>
</ul>
<p>I believe the above shows, beyond a reasonable doubt, that NULL semantics are unintuitive, and if viewed according to most of the &#8220;standard explanations,&#8221; highly inconsistent. This may seem minor; that is, if you&#8217;re writing SQL you can overcome these things with training. But it is not minor, because NULL semantics are designed to make you <em>think</em> you understand them, and <em>think</em> that the semantics are intuitive, and <em>think</em> that it&#8217;s part of some ingenious consistent system for managing missing information. But none of those things are true.</p>
<p>I have seen lots of discussions about NULL in various forums and mailing lists. Many of the participants are obviously intelligent and experienced, and yet make bold statements that are, quite simply, false. I&#8217;m writing this article to make two important points:</p>
<ol>
<li>There is a good case to be made that NULL semantics are very counterproductive; as opposed to a simple &#8220;error early&#8221; system that forces you to write queries that explicitly account for missing information (e.g. with <code>COALESCE</code>). &#8220;Error early&#8221; is a more mainstream approach, similar to null pointers in java or None in python. If you want compile-time checking, you can use a construct like Maybe in haskell. SQL attempts to pass along the problem, hoping the next operator will turn ignorance into knowledge &#8212; but it does not appear that anyone thought through this idea, quite frankly.</li>
<li>You should not attempt to apply your intellect to NULL, it will lead you in the wrong direction. If you need to understand it, understand it, but always treat it with skepticism. Test the queries, read the standard, do what you need to do, but do <strong>not<em> </em></strong>attempt to extrapolate.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://thoughts.j-davis.com/2009/08/02/what-is-the-deal-with-nulls/feed/</wfw:commentRss>
		<slash:comments>45</slash:comments>
		</item>
	</channel>
</rss>
