<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://www.skepticats.com/LnBlog/themes/default/styles/rss.css" ?>
<rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<link>http://linlog.skepticats.com/feeds/Database_news.xml</link>
<title>LinLog</title>
<description>Linux, Programming, and Computing in General</description>
<generator>LnBlog 1.0.0</generator>
<item>
<title>Formatting with psql  </title>
<link>http://linlog.skepticats.com/entries/2009/08/Formatting_with_psql.php</link>
<description>
&lt;p&gt;Yes, this is yet another &amp;quot;reminder to myself&amp;quot; Postgres post, because I've had to &lt;a href=&quot;http://www.postgresql.org/files/documentation/books/aw_pgsql/node143.html&quot;&gt;look this up&lt;/a&gt; at least 3 times.&lt;/p&gt;&lt;p&gt;To turn on expanded query output formatting in psql, the Postgres command-line client, run either &lt;code&gt;\pset expanded&lt;/code&gt; or simply &lt;code&gt;\x&lt;/code&gt;.  They both do the same thing - make Postgres output each column in a result set as a separate line.  This is equivalent to the mysql command-line client trick of ending the query with &lt;code&gt;\G&lt;/code&gt; instead of a semi-colon.&lt;/p&gt;&lt;p&gt;Incidentally both of the above commands are boolean toggles.  You run them once to turn on expanded formatting and run them again to turn it off.&lt;/p&gt;
</description>
<author>pageer@skepticats.com (Peter Geer)</author>
<comments>http://linlog.skepticats.com/entries/2009/08/18_0918/comments/</comments>
<guid>http://linlog.skepticats.com/entries/2009/08/18_0918/</guid>
</item>
<item>
<title>Timestamps in PostgreSQL </title>
<link>http://linlog.skepticats.com/entries/2009/07/Timestamps_in_PostgreSQL.php</link>
<description>
&lt;p&gt;So at my new job (maybe I'll post something about that later), we use PostgreSQL for our &lt;abbr title=&quot;Relational DataBase Management System&quot;&gt;RDBMS&lt;/abbr&gt;.  And, for reasons I won't get into, our application stores dates as UNIX timestamps, rather than, you know, actual &lt;em&gt;dates&lt;/em&gt;.  Thus this quick note to myself so I don't have to keep looking up how to convert between the two.&lt;/p&gt;&lt;p&gt;Date to UNIX timestamp in Postgres (from &lt;a href=&quot;http://www.archonet.com/pgdocs/date-to-epoch.html&quot;&gt;this page&lt;/a&gt;):&lt;br /&gt;&lt;code&gt;select date_part('epoch',now()) as unixtime; -- This will do it.&lt;br /&gt;select extract('epoch' from now()) as unixtime;  -- ... and so will this.&lt;/code&gt;&lt;/p&gt;&lt;p&gt;UNIX timestamp to Postgres TIMESTAMP (from &lt;a href=&quot;http://www.postgresonline.com/journal/index.php?/archives/3-Converting-from-Unix-Timestamp-to-PostgreSQL-Timestamp-or-Date.html&quot;&gt;this page&lt;/a&gt;):&lt;br /&gt;&lt;code&gt;SELECT TIMESTAMP 'epoch' + 1195374767 * INTERVAL '1 second';&lt;/code&gt;&lt;/p&gt;
</description>
<author>pageer@skepticats.com (Peter Geer)</author>
<comments>http://linlog.skepticats.com/entries/2009/07/23_1600/comments/</comments>
<guid>http://linlog.skepticats.com/entries/2009/07/23_1600/</guid>
</item>
<item>
<title>Weird index breakage   </title>
<link>http://linlog.skepticats.com/entries/2008/10/Weird_index_breakage.php</link>
<description>
&lt;p&gt;Here's an odd one.  So I was trying to run a simple query for a data import I'm working on.  I've got about 11,000 rows in the media table with a site_id of 2 and I wanted to see which media types were represented.  So I ran this:&lt;/p&gt;&lt;p&gt;&lt;code&gt;SELECT DISTINCT media_type FROM media WHERE site_id = 2;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;To my surprise, this returned...nothing!  No rows at all.  So I took off the &lt;code&gt;DISTINCT&lt;/code&gt;, just to check, and got back all 11,000 rows.  What the heck?&lt;/p&gt;&lt;p&gt;Something was obviously wrong.  This should never happen - if there are rows with the correct site_id, that query should always return &lt;em&gt;something&lt;/em&gt;.  So what now?  Might as well look at the query plan:&lt;/p&gt;&lt;p&gt;&lt;code&gt;mysql&amp;gt; explain extended select distinct media_type from media where site_id = 2 \G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;           id: 1&lt;br /&gt;  select_type: SIMPLE&lt;br /&gt;        table: media&lt;br /&gt;         type: range&lt;br /&gt;possible_keys: idx_media_site_media_type,idx_frontpage&lt;br /&gt;          key: idx_typesiteid&lt;br /&gt;      key_len: 2&lt;br /&gt;          ref: NULL&lt;br /&gt;         rows: 15&lt;br /&gt;        Extra: Using where; Using index for group-by&lt;br /&gt;1 row in set, 1 warning (0.00 sec)&lt;/p&gt;&lt;p&gt;mysql&amp;gt; show warnings \G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;  Level: Note&lt;br /&gt;   Code: 1003&lt;br /&gt;Message: select distinct `cms`.`media`.`media_type` AS `media_type` from `cms`.`media` where (`cms`.`media`.`site_id` = 2)&lt;br /&gt;1 row in set (0.00 sec)&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Nothing out of the ordinary there.  It's using the idx_typesiteid index, which is correct.  Maybe that index is broken.  Let's try another one:&lt;/p&gt;&lt;p&gt;&lt;code&gt;select distinct media_type from media use index (idx_media_site_media_type) where site_id = 2;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Yup, it worked that time - I got 5 rows back, which is about what I was expecting.  I get the same results if I use &lt;br /&gt;&lt;code&gt;IGNORE INDEX (idx_typesiteid)&lt;/code&gt; as the index hint.  So idx_typesiteid must just be broken.  I should probably fix that, but it was getting into peak hours for our site and I didn't want to run an &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; or anything that would lock the media table.&lt;/p&gt;&lt;p&gt;But wait, there's one other weird thing.  Just for the heck of it, I tried running the query with a few different index hints.  And guess what: the query still works if I use &lt;code&gt;FORCE INDEX (idx_typesiteid)&lt;/code&gt;.  Does that make sense to anybody?  So if I &lt;em&gt;ignore&lt;/em&gt; that index it works, and if I &lt;em&gt;force&lt;/em&gt; the same index, it works, but if I give no hint, it claims to use that index and the query returns no data.  I got nothin' on that one.&lt;/p&gt;
</description>
<author>pageer@skepticats.com (Peter Geer)</author>
<comments>http://linlog.skepticats.com/entries/2008/10/30_2322/comments/</comments>
<guid>http://linlog.skepticats.com/entries/2008/10/30_2322/</guid>
</item>
<item>
<title>MySQL comment weirdness </title>
<link>http://linlog.skepticats.com/entries/2008/10/MySQL_comment_weirdness.php</link>
<description>
&lt;p&gt;Here's one I discovered for the first time yesterday - &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/comments.html&quot;&gt;MySQL doesn't actually use the ANSI SQL comment sequence&lt;/a&gt;.  Who knew?&lt;/p&gt;&lt;p&gt;For those who are a little rusty on such things, ANSI SQL-92 specifies the comment character as a doule dash (--).  Anything from a double dash to the end of a line is a comment.&lt;/p&gt;&lt;p&gt;Well, in MySQL, that doesn't actually work.  You &lt;em&gt;have&lt;/em&gt; to have a &lt;em&gt;space&lt;/em&gt; (or control character) after the double dash for MySQL to treat is as a comment.  This is good style anyway, but MySQL makes it a hard requirement.  Apparently the &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html&quot;&gt;reason for this&lt;/a&gt; is that it can cause conflicts with software that auto-generates really crappy queries.  &lt;/p&gt;&lt;p&gt;Is it just me, or does that seem like a really gratuitous change?  I mean, I can see their reasons - it would be nice if an auto-generated query like &lt;code&gt;UPDATE account SET credit=credit--1&lt;/code&gt; actually worked instead of reducing to a no-op.  But, on the other hand, is it really a good idea to change the database server because some vendor is too lazy to make their query-generator produce the more correct and logically equivalent &lt;code&gt;UPDATE account SET credit=credit+1&lt;/code&gt; instead?  I don't know.  I'm sure they had their reasons, but it just feels like a half-baked hack to me.&lt;/p&gt;
</description>
<author>pageer@skepticats.com (Peter Geer)</author>
<comments>http://linlog.skepticats.com/entries/2008/10/14_2333/comments/</comments>
<guid>http://linlog.skepticats.com/entries/2008/10/14_2333/</guid>
</item>
<item>
<title>Keys and NULLs  </title>
<link>http://linlog.skepticats.com/entries/2008/10/Keys_and_NULLs.php</link>
<description>
&lt;p&gt;Well, the cat is currently laying on the book I was trying to read, so I guess I might as well blog.&lt;/p&gt;&lt;p&gt;Note to self: the rule in SQL is that you can have NULLs in &lt;em&gt;foreign&lt;/em&gt; keys, but not in &lt;em&gt;primary&lt;/em&gt; keys.  Edwin asked me a question related to this the other day and I had to stop and think about it for a couple of minutes, so I figured I'd write it out to reinforce the concept in my own mind.&lt;/p&gt;&lt;p&gt;When you think about it, these rules make perfect sense.  Since NULLs in SQL denote an unknown or inapplicable value, having one in a primary key would be nonsense, because a primary key must uniquely identify a row.  Having a NULL in the key would mean part of the unique value was unknown.  (Note that you can't say that a tuple with a NULL in it is unique because one NULL is not equal to another due to the 3-valued logic used by SQL.)&lt;/p&gt;&lt;p&gt;As for foreign keys, SQL  gives the &amp;quot;benefit of the doubt.&amp;quot;  If you think of a NULL as an unknown value which &lt;em&gt;may&lt;/em&gt; later become known, this makes sense.  Sometimes you might have to add the values of foriegn keys in multiple operations, which would not be allowed if NULLs were blocked by the constraint.&lt;/p&gt;&lt;p&gt;From a logical point of view, this is kind of an interesting case as well.  You can view a foreign key constraint check as a conjunction of equivalence checks.  For example if T1(c1, c2) is foreign keyed to T2(c1, c2), then the constraint check can be viewed as the expression &lt;code&gt;T1.c1 = T2.c1 AND T1.c2 = T2.c2&lt;/code&gt;.  In other words, if all the key fields match on both records, the constraint is satisfied.  If not, it fails.  However, with NULLs, the value of one of the conjuncts would be NULL, which would render the entire expression NULL.  &lt;/p&gt;&lt;p&gt;But what would that mean?  &lt;/p&gt;&lt;p&gt;The &lt;abbr title=&quot;DataBase Management System&quot;&gt;DMBS&lt;/abbr&gt; can't say that it &lt;em&gt;doesn't know&lt;/em&gt; if a relational constraint holds or not.  So, given the interpretation of NULL, it makes sense to use the &amp;quot;benefit of the doubt&amp;quot; principle and defer final judgement on the constraint until all the NULLs are filled in.&lt;/p&gt;
</description>
<author>pageer@skepticats.com (Peter Geer)</author>
<comments>http://linlog.skepticats.com/entries/2008/10/11_2339/comments/</comments>
<guid>http://linlog.skepticats.com/entries/2008/10/11_2339/</guid>
</item>
<item>
<title>Updating from the same table     </title>
<link>http://linlog.skepticats.com/entries/2008/06/Updating_from_the_same_table.php</link>
<description>
&lt;p&gt;Last time, I was bitching about &lt;a href=&quot;http://linlog.skepticats.com/entries/2008/06/Another_reason_to_hate_MySQL.php&quot;&gt;doing an update based on a select from the same table in MySQL&lt;/a&gt;.  Well, after reading the chapter on &amp;quot;Views, Derived Tables, Materialized Tables, and Temporary Tables&amp;quot; in &lt;em&gt;SQL for Smarties&lt;/em&gt;, followed by a search of the MySQL documentation, I figured out a way around that annoying limitation.&lt;/p&gt;&lt;p&gt;If you recall from last time, the query that wasn't working looked something like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mysql&amp;gt; UPDATE test_tbl SET val2 = (SELECT val2 FROM test_tbl WHERE val1 = 1) WHERE val1 = 3;&lt;br /&gt;ERROR 1093 (HY000): You can't specify target table 'test_tbl' for update in FROM clause&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Basically, this is doing an update and setting a column to the value of a scalar subquery.  The catch is that, in MySQL, this doesn't work when the select and update are on the same table.&lt;/p&gt;&lt;p&gt;Well, the trick is that you have to make make MySQL materialize the subquery.  I actually decided to try that after reading Joe Celko's story about views in the early days of DB2.  At the time, it was using inline-expansion for views, which would sometimes generate invalid SQL.  Thus it was sometimes necessary to make the database materialize the view.  &lt;/p&gt;&lt;p&gt;Well, I figured the same thing might apply here.  And so, after a little inspiration from the MySQL manual, here's a working version of the same query:&lt;/p&gt;&lt;p&gt;&lt;code&gt;UPDATE test_tbl SET val2 = (SELECT val2 FROM (SELECT val2 FROM test_tbl AS tmp1 WHERE val1=1) AS tmp2) WHERE val1 = 3;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;I stole &lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/subquery-restrictions.html&quot;&gt;the sub-subquery idea&lt;/a&gt; from the MySQL manual.  It is, of course, completely gratuitous from a logical standpoint, but it forces MySQL to materialize the subquery.  That, in turn, allows us to bypass the &amp;quot;no updating the same table&amp;quot; restriction, since we're technically selecting from a temporary table.&lt;/p&gt;&lt;p&gt;So there you have it!  I was wrong about not being able to do that.  It just takes a little finagling.  Of course, I still think MySQL should be smart enough to make a temporary table on its own, but at least the end result is still possible.&lt;/p&gt;
</description>
<author>pageer@skepticats.com (Peter Geer)</author>
<comments>http://linlog.skepticats.com/entries/2008/06/16_1401/comments/</comments>
<guid>http://linlog.skepticats.com/entries/2008/06/16_1401/</guid>
</item>
<item>
<title>Another reason to hate MySQL      </title>
<link>http://linlog.skepticats.com/entries/2008/06/Another_reason_to_hate_MySQL.php</link>
<description>
&lt;p&gt;I'm currently about half way through &lt;a href=&quot;http://www.amazon.com/Joe-Celkos-SQL-Smarties-Programming/dp/0123693799/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1212702882&amp;amp;sr=8-1&quot;&gt;Joe Celko's &lt;em&gt;SQL for Smarties&lt;/em&gt;&lt;/a&gt; and I've got to tell you - it's spoiling me as a &lt;acronym title=&quot;Linux, Apache, MySQL, and PHP&quot;&gt;LAMP&lt;/acronym&gt; developer.  &lt;/p&gt;&lt;p&gt;Let me start out by saying that this book is a must-read for any developer who works with databases.  Even if you've been writing SQL for years, you need to read this book.  In fact, unless you sat on the ANSI SQL-92 committee &lt;em&gt;with Joe Celko&lt;/em&gt;, you can benefit from reading this book.  I've been &amp;quot;doing SQL&amp;quot; for years, and I've learned a bunch of new tricks and rediscovered things I had forgoten from reading this.  And not only is it informative on SQL, but it's also entertaining and informative on other subjects (e.g., in one chapter, Joe describes the history of the soundex algorithm).&lt;/p&gt;&lt;p&gt;The problem with getting more SQL-literate is that I have to work with MySQL.  Now, I don't want to rag on MySQL too much - it's good &lt;em&gt;for what it is&lt;/em&gt;.  And what it is is an engine for storing data and getting it back out in an efficient manner.  The problem is that it's really not focused on implementing standard SQL in any deep way.  &lt;/p&gt;&lt;p&gt;My particular annoyance today came when I was writing code to do a simple update.  The situation is that I was working on a new variation on the picture galleries for our site, and realized that I wasn't associating a thumbnail image with the galleries I was creating.  By virtue of the way our codebase works (all of which pre-dates my involvement), our picture galleries consist of &lt;em&gt;n+1&lt;/em&gt; rows in our main media table, where &lt;em&gt;n&lt;/em&gt; is the number of pictures in the gallery - one row per picture and another row for the gallery meta-item.  Because of the way I had written my creation methods in PHP and added my foreign key constraints in the database, the path of least resistance was to just set the gallery thumbnail to the same value as one of the pictures.  Here's a simplified example of the basic query I used:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;-- Create a sample test and populate it with data.&lt;br /&gt;CREATE TABLE test_tbl (id INT, val2 INT);&lt;br /&gt;INSERT INTO test_tbl VALUES (1, 2);&lt;br /&gt;INSERT INTO test_tbl VALUES (3, NULL);&lt;br /&gt;-- Here's the query I was running.&lt;br /&gt;UPDATE test_tbl SET val2 = (SELECT val2 FROM test_tbl WHERE id = 3) WHERE id=2;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;In the routine as I had written it, I had the IDs of the gallery and all the pictures, but that was it.  With a query like this, I could just clone the thumbnail of one picture to the gallery in a single query - no need to clutter the code with any lookups or suchlike.  &lt;/p&gt;&lt;p&gt;Of course, if you know MySQL, you may already know that this didn't work.  When I  tried running this, I got:&lt;br /&gt;&lt;code&gt;ERROR 1093 (HY000): You can't specify target table 'test_tbl' for update in FROM clause&lt;/code&gt;&lt;br /&gt;I was actually kind of surprised by this.  I mean, this query isn't all that exotic.  It's perfectly valid in standard SQL and it works in PostgreSQL.  Why not MySQL?&lt;/p&gt;&lt;p&gt;Well, the answer seems to be that MySQL disregards the conceptual execution model of subqueries.  I say this because, if you do the subquery on &lt;em&gt;a different table than the one being updated&lt;/em&gt;, then MySQL doesn't have a problem with it.  Example:&lt;code&gt;&lt;br /&gt;-- Create a second table and add a row.&lt;br /&gt;CREATE TABLE extra_tbl (id INT, val2 INT);&lt;br /&gt;INSERT INTO test_tbl VALUES (3, 9);&lt;br /&gt;-- This one works just find in MySQL.&lt;br /&gt;UPDATE test_tbl SET val2 = (SELECT val2 FROM extra_tbl WHERE id = 3) WHERE id=2;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;You see, according to Joe Celko (read the book!), the execution model of a subquery is that it creates a temporary table.  So, in the case of my first sample query, it would create a copy of test_tbl, find the target row in that, and then update test_tbl.  If you didn't use that model, then it would make some sense that you can't update the same table you're searching in.  (Note: Of course, other databases don't &lt;em&gt;actually&lt;/em&gt; create temporary tables for every subquery - they just produce the same result as if they did.)&lt;/p&gt;&lt;p&gt;I guess my problem is that I'm just starting to expect too much from MySQL.  I've reached the point that I find it annoying that the default storage engine (MyISAM) doesn't support foreign key constraints.  I find it even more annoying that MySQL doesn't support the enormously useful CHECK constraints at all.  And, really, is it absolutely necessary to invent new versions of standard functions, mangle standard functions (what the hell did they do to CAST()?), or to disable the ANSI string concatenation operator by default?  It all just just seems superfluous.  After all, PostgreSQL didn't have much trouble with the ANSI standard.  Why can't MySQL get it?&lt;/p&gt;&lt;p&gt;Oh, well.  I guess it could be worse.  At least now I have the wisdom to know what I'm missing.  In days gone by, I thought MS Access seemed just fine as a database.  Back then, I didn't declare primary keys and didn't even know what indexes were!  By comparison to that, MySQL looked like freakin' Oracle!  If only I hadn't been so young and stupid then, think of where I'd be now....&lt;/p&gt;
</description>
<author>pageer@skepticats.com (Peter Geer)</author>
<comments>http://linlog.skepticats.com/entries/2008/06/05_2303/comments/</comments>
<guid>http://linlog.skepticats.com/entries/2008/06/05_2303/</guid>
</item>
</channel>
</rss>