<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xml:base="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
 <title>Drupal High</title>
 <link>http://drupalhigh.onsugar.com</link>
 <description>Simple musings of a Drupal developer.</description>
 <language>en</language>
 <atom:link href="http://drupalhigh.onsugar.com/tag/SQL/rss" rel="self" type="application/rss+xml" />
<item>
 <title>Sequential updates with SQL</title>
 <link>http://drupalhigh.onsugar.com/6215939</link>
 <description>&lt;a href=&quot;http://drupalhigh.onsugar.com/6215939&quot;&gt;&lt;/a&gt;&lt;p&gt;Oh no! A series of posts were uploaded to the server in reverse order!&lt;/p&gt;
&lt;p&gt;The site uses a view that sorts posts into chronological order (node created time). We can&#039;t change the view just to handle these errant posts. We could update all the node created times one at a time in the database, but there&#039;s just too many - it&#039;ll take all day!&lt;/p&gt;
&lt;p&gt;I knew it would be possible to fix this with a little SQL, but I&#039;ve never had to do something like this before. After some reading and research, this is what I came up with&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #800000; color: #ffcc99;&quot;&gt;SET @rownum := 0;&lt;br /&gt;UPDATE node SET created = UNIX_TIMESTAMP(DATE_ADD(NOW(), INTERVAL (SELECT @rownum := @rownum + 1) MINUTE)) WHERE nid &amp;gt; 100 AND nid &amp;lt; 200 ORDER BY created DESC;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;There&#039;s a lot going on in this statement:&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #800000; color: #ffcc99;&quot;&gt;SET @rownum := 0;&lt;/span&gt; initializes the rownum variable to 0.&lt;/p&gt;
&lt;p&gt;You can mostly ignore the date stuff - Drupal uses integer timestamps while MySQL prefers real Dates. My plan is to use the DATE_ADD() function to add ever larger amounts to the starting time (NOW()). This could be a lot simpler just leaving everything as integers, but I like the challenge :)&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #800000; color: #ffcc99;&quot;&gt;INTERVAL (SELECT @rownum := @rownum + 1) MINUTE&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This is really the key part of the statement. We&#039;re doing a subselect right in the middle of the UPDATE statement. This causes rownum to be incremented by 1, and the new value returned, which is then used to update just this row. When the next row is updated, rownum will be incremented again, and so on. So when each node gets its created time updated, the first will be now(), the second now() + 1 minute, the third now() + 2 minutes, etc.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #800000; color: #ffcc99;&quot;&gt;WHERE nid &amp;gt; 100 AND nid &amp;lt; 200&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The where clause just specifies which nodes we&#039;re updating, nothing special but it is critical. Make sure you&#039;re only affecting the rows you want to update.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #800000; color: #ffcc99;&quot;&gt;ORDER BY created DESC&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This is the other key part. Ordering for updates works just like it does for select statements. All the rows are getting updated, this lets us specify in what order the updated happen.&lt;/p&gt;
&lt;p&gt;So now when we put it all together, the magic happens. The nodes were uploaded in reverse order, remember? That means when we sort by created time in descending order, we get the newest ones first - those are the ones that should be the oldest. So when the update happens, the newest node gets the oldest time, and second newest gets the second oldest, ... all the way until the oldest node gets the newest time.&lt;/p&gt;
&lt;p&gt;And so they end up with reversed created times, and the view will now show them in the correct order.&lt;/p&gt;
</description>
 <comments>http://drupalhigh.onsugar.com/6215939#comment</comments>
 <category domain="http://www.teamsugar.com/category/drupal">drupal</category>
 <category domain="http://www.teamsugar.com/tag/mysql">mysql</category>
 <category domain="http://www.teamsugar.com/tag/SQL">SQL</category>
 <pubDate>Fri, 13 Nov 2009 14:14:58 -0800</pubDate>
 <dc:creator>krs</dc:creator>
 <guid>http://drupalhigh.onsugar.com/6215939</guid>
</item>
<item>
 <title>update_sql is not my friend</title>
 <link>http://drupalhigh.onsugar.com/2672756</link>
 <description>&lt;a href=&quot;http://drupalhigh.onsugar.com/2672756&quot;&gt;&lt;/a&gt;&lt;p&gt;Oh &lt;a href=&quot;http://api.drupal.org/api/function/update_sql/5&quot;&gt;update_sql()&lt;/a&gt;, second most unloved of the drupal database functions (&lt;a href=&quot;http://drupal.org/node/299176&quot;&gt;db_rewrite_sql()&lt;/a&gt; is worse)! If you&#039;ve never used it, it is basically a wrapper for db_query() that you can use in hook_update_N() hooks in a module .install file. You may never need to write one of these hooks unless you maintain a module; or like me you prefer to make database changes via code when I&#039;m pushing some new features out to dev, stage, and live servers.&lt;/p&gt;
&lt;p&gt;The Drupal 6 and 7 versions of the documentation for this function do mention that &quot;%-substitution parameters are not supported.&quot; Definitely also true for the Drupal 5 version I&#039;m still working with. So you can&#039;t do variable substitution like you do with db_query() and most of the time thats not a big deal.&lt;/p&gt;
&lt;p&gt;There is one &lt;b&gt;very&lt;/b&gt; important time though.&lt;/p&gt;
&lt;p&gt;When using db_query(), you call it with a syntax like db_query($sql, $variable1, $variable2); Now, you know about database prefixes, and always sing curly braces around your table names in FROMs and JOINs, and that lets Drupal work on multisite installs very well, or talk to more than one DB at a time. So the $sql part of that function call &lt;b&gt;always&lt;/b&gt; gets passed through a strtr(), or in English, PHP&#039;s string translate function that converts every instace of &#039;{&#039; to the right prefix (generally just deletes it). You have no choice about this, and no way to prevent it from getting every single { and }!&lt;/p&gt;
&lt;p&gt;So far so good, because you only use curly braces around the table names, and that works out just fine, right?&lt;/p&gt;
&lt;p&gt;Now enter update_sql(). This function doesn&#039;t support variable substitution, so your function calls look are just update_sql($sql).&lt;/p&gt;
&lt;p&gt;Like update_sql(&quot;UPDATE {node} SET title = &#039;something else&#039; WHERE nid = 10&quot;); - that is, everything has to be passed as part of a single SQL statement (the $sql part above). The SQL statement that always gets run through strtr() looking for &#039;{&#039; and &#039;}&#039;. Which, if you are trying to update a serialized array, or a block&#039;s visibility code with PHP, or just want to use a { in a node title, it will be deleted. Every time, without exception.&lt;/p&gt;
&lt;p&gt;So if you&#039;re using update_sql() and any part of the data contains a &#039;{&#039; or &#039;}&#039; that you need to keep intact - rewrite it as a db_query() with variable substitution. The strtr() will operate on the $sql part, and the $values get substituted in later and stay intact.&lt;/p&gt;</description>
 <comments>http://drupalhigh.onsugar.com/2672756#comment</comments>
 <category domain="http://www.teamsugar.com/category/drupal">drupal</category>
 <category domain="http://www.teamsugar.com/tag/SQL">SQL</category>
 <category domain="http://www.teamsugar.com/tag/drupal5">drupal5</category>
 <category domain="http://www.teamsugar.com/tag/strtr()">strtr()</category>
 <category domain="http://www.teamsugar.com/tag/curly braces">curly braces</category>
 <category domain="http://www.teamsugar.com/tag/escaping">escaping</category>
 <pubDate>Wed, 07 Jan 2009 22:51:53 -0800</pubDate>
 <dc:creator>krs</dc:creator>
 <guid>http://drupalhigh.onsugar.com/2672756</guid>
</item>
</channel>
</rss>
