<?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>Coffee on the Keyboard &#187; How To</title>
	<atom:link href="http://coffeeonthekeyboard.com/tag/how-to/feed/" rel="self" type="application/rss+xml" />
	<link>http://coffeeonthekeyboard.com</link>
	<description>by James Socol</description>
	<lastBuildDate>Mon, 06 Feb 2012 23:33:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/>		<item>
		<title>All Starred Messages in Thunderbird 3</title>
		<link>http://coffeeonthekeyboard.com/all-starred-messages-in-thunderbird-3-369/</link>
		<comments>http://coffeeonthekeyboard.com/all-starred-messages-in-thunderbird-3-369/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 17:11:02 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[gtd]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[thunderbird]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=369</guid>
		<description><![CDATA[I &#8220;star&#8221; messages in Thunderbird pretty frequently as a reminder to go back and look at them. But it doesn&#8217;t usually work. Why not? There is no easy way to go back and look at starred messages by default. I could resort each folder, looking for stars, but that&#8217;s annoying. I was hoping one of [...]]]></description>
			<content:encoded><![CDATA[<p>I &#8220;star&#8221; messages in Thunderbird pretty frequently as a reminder to go back and look at them. But it doesn&#8217;t usually work.</p>
<p>Why not? There is no easy way to go back and look at starred messages by default. I could resort each folder, looking for stars, but that&#8217;s annoying. I was hoping one of the Smart Folders would be &#8220;Starred Messages&#8221; but, sadly, I was wrong.</p>
<p>You can&#8217;t even easily search for starred messages!</p>
<p>But you can create a new saved search. Here&#8217;s how:</p>
<ol>
<li>Go to File &gt; New &gt; Saved Search&#8230;</li>
<li>Name it something like &#8220;Starred&#8221;</li>
<li>Set &#8220;Create as a subfolder of:&#8221; to wherever you&#8217;d like the folder to live.</li>
<li>Click &#8220;Choose&#8221; to pick which folders to search.</li>
<li>Change the filter to &#8220;Status&#8221; &#8220;is&#8221; &#8220;Starred&#8221;.</li>
<li>Save it.</li>
</ol>
<p>Then you can open your saved search in a new tab, or just leave it in the list of folders.</p>
<p>Posted here to save someone else some time.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/all-starred-messages-in-thunderbird-3-369/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Identity 2.0 &#8211; A Primer</title>
		<link>http://coffeeonthekeyboard.com/identity-20-a-primer-106/</link>
		<comments>http://coffeeonthekeyboard.com/identity-20-a-primer-106/#comments</comments>
		<pubDate>Tue, 01 Jul 2008 16:13:36 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[2.0]]></category>
		<category><![CDATA[authority]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[identity]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[social messaging]]></category>
		<category><![CDATA[Social Networking]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[Web 2.0]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/identity-20-a-primer-106/</guid>
		<description><![CDATA[Google your name. Right now. I&#8217;ll wait. Put your name here: Good. What came up? Look at the first page of results and ask yourself these questions about each one: Is it really me? Did I create this? Do I control this? You need to be able to say &#8220;yes&#8221; to all of these for [...]]]></description>
			<content:encoded><![CDATA[<p>Google your name. Right now. I&#8217;ll wait.</p>
<form action="http://www.google.com/search" method="get" onsubmit="window.open('http://www.google.com/search?q='+this.q.value,'','');return false;"><label for="google-search">Put your name here:</label></p>
<input name="q" id="google-search" size="30" type="text" />
<input value="Google Thyself" type="submit" /></form>
<p>Good. What came up?</p>
<p>Look at the first page of results and ask yourself these questions about each one:</p>
<ol>
<li>Is it really me?</li>
<li>Did I create this?</li>
<li>Do I control this?</li>
</ol>
<p>You need to be able to say &#8220;yes&#8221; to all of these for at least the top two or three results. (As I write this, the <a href="http://www.rssmeme.com/">RSSmeme</a> page <a href="http://www.rssmeme.com/user/15663/">repeating my Google Reader shared items</a> has crawled above my blog, and I&#8217;m upset about it.)</p>
<h3>Creating Identity</h3>
<p>I&#8217;m lucky. My last name is very rare, so even if you <a href="http://www.google.com/search?q=Socol">Google just &#8220;Socol&#8221;</a>  I come in second—only to <a href="http://speedchange.blogspot.com/">my father</a>, and ahead of Wikipedia. You may not be so lucky, saddled with a name like Jones or Smith or, even worse, you might have the <a href="http://www.youtube.com/watch?v=145mqJduiO4">same name as a celebrity</a>. You may have an uphill battle.</p>
<p>People with common names need to get creative. It can be as simple as adding an initial—my friend became <a href="http://www.myspace.com/alecrjohnston">Alec R. Johnston</a> to distinguish himself. Something a little more creative—Lisa Bettany named her blog <a href="http://www.mostlylisa.com/">Mostly Lisa</a>. Or you can geek out, like Ben Lew, who uses the name <a href="http://n0s0ap.com/">n0s0ap</a>. (Those are zeros.)</p>
<p>Ben uses the name n0s0ap on <a href="http://del.icio.us/n0s0ap">del.icio.us</a>, <a href="http://flickr.com/photos/n0s0ap">flickr</a>, <a href="http://www.last.fm/user/n0s0ap/">Last.fm</a>, <a href="http://digg.com/users/n0s0ap">Digg</a>, <a href="http://twitter.com/n0s0ap">Twitter</a>, etc. Lisa uses a combination of &#8220;<a href="http://www.viddler.com/explore/MostlyLisa/">MostlyLisa</a>&#8221; and &#8220;<a href="http://twitter.com/lisabettany">LisaBettany</a>.&#8221; I use a combination of an old name, &#8220;<a href="http://www.last.fm/user/urbaneexistance/">UrbaneExistance</a>&#8221; (I know it&#8217;s spelled wrong) and &#8220;<a href="http://friendfeed.com/jamessocol">JamesSocol</a>&#8221; for all new registrations.</p>
<p>But all of us, Alec, Ben, Lisa, and I, make sure our real names are linked to our identities. It&#8217;s no Clark Kent: n0s0ap <em>is</em> Ben Lew, with the glasses on or off.</p>
<h3>Owning Identity</h3>
<p>Do you own your own domain name? Why not? Go buy it. Now. Go!</p>
<p>I have this conversation with friends all the time. Would you want someone signing your name on paper documents? Of course not, so why would you let them do the same thing online? I own jamessocol.com, jamessocol.net, and jamessocol.org, just so no one else does. Even if you do nothing but have it redirect to your social network of choice, you should own your name.</p>
<p>If your name is taken, reread the last section and get creative.</p>
<p>Now, about those <strong>social networks</strong>. You don&#8217;t need to be on every one, but get on a few, build a profile, and put your name on it. You can create and control your own Facebook and MySpace pages without knowing a single HTML tag. Once you&#8217;ve got a name, whether it&#8217;s your real name or something else, use it. last.fm/user/<strong>you</strong>. twitter.com/<strong>you</strong>.</p>
<h3>Controlling Identity</h3>
<p>The best way I&#8217;ve found to control what the web knows about you is to start your own propaganda campaign. Put your name on a lot of things, preferably with links back to your own site.</p>
<p>An easy way to start is by commenting. Blog comments help the most, since you spread that influence around the whole internet, but within MySpace or Facebook posting real, meaningful, interesting comments on profiles and walls will make sure people think of you when they hear your name.</p>
<p>If you have the time, try blogging. There are a lot of blogs with <a href="http://problogger.com/">great</a> <a href="http://chrisbrogan.com/">advice</a>, but you can always just &#8220;write what you know.&#8221; Once you find your voice, the writing flows.</p>
<p>What else? It depends what you like. If you take pictures, get a <a href="http://flickr.com/photos/urbaneexistence/">Flickr</a> stream. <a href="http://www.last.fm/user/urbaneexistance/">Last.fm</a> is a great way to share and find music you like. <a href="http://www.goodreads.com/profile/jamessocol">GoodReads</a> is a similar site for books. <a href="http://twitter.com/jamessocol">Twitter</a> is great for finding people with similar interests and building connections. <a href="http://linkedin.com/in/jamessocol">LinkedIn</a> is a professional social network, particularly good for people in marketing or new media. <a href="http://speedchange.blogspot.com/">Blogger</a>, while not the best blogging platform, has some good community features. <a href="http://en.wikipedia.org/wiki/List_of_social_networking_websites">There is a lot out there</a>.</p>
<h3>Be Yourself</h3>
<p>Don&#8217;t let someone else be you! Own your own identity and be proud of it. It will help you <a href="http://coffeeonthekeyboard.com/expertise-and-authority-20-104/" title="build authority">build authority</a> and when a potential employer or client googles you, they&#8217;ll get a good idea about you from the first page of results.</p>
<p>What else, 2.0-savvy readers? What did I forget?</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/identity-20-a-primer-106/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Better Living through Memcached</title>
		<link>http://coffeeonthekeyboard.com/better-living-through-memcached-85/</link>
		<comments>http://coffeeonthekeyboard.com/better-living-through-memcached-85/#comments</comments>
		<pubDate>Mon, 19 May 2008 15:00:54 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[instructions]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[quality]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[useful]]></category>
		<category><![CDATA[Web 2.0]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/better-living-through-memcached-85/</guid>
		<description><![CDATA[I wanted to put something specific in the title, like &#8220;Speed up your service&#8221; or &#8220;Reduce server load&#8221; or &#8220;Limit database calls&#8221; or&#8230; You see why I chose &#8220;Better Living.&#8221; Memcached is a memory caching system with an obvious name. It allows you to store basically any data that can be serialized into a giant, [...]]]></description>
			<content:encoded><![CDATA[<p>I wanted to put something specific in the title, like &#8220;Speed up your service&#8221; or &#8220;Reduce server load&#8221; or &#8220;Limit database calls&#8221; or&#8230; You see why I chose &#8220;Better Living.&#8221;</p>
<p><a href="http://danga.com/memcached/">Memcached</a> is a memory caching system with an obvious name. It allows you to store basically any data that can be serialized into a giant, memory-resident hash, then retrieve it with its unique key.</p>
<p>Imagine not querying your database on every request, and you only begin to get a sense of how useful this is.</p>
<p>Let&#8217;s go through a simple, single-server setup.<span id="more-85"></span></p>
<h3>Installing Memcached</h3>
<p>First you&#8217;ll need to make sure <a href="http://www.monkey.org/~provos/libevent/">libevent</a> is installed. Easy enough through yum or apt-get.</p>
<p><a href="http://danga.com/memcached/download.bml">Download Memcached</a> and untar it. Run the <code>configure</code> script. You can probably do this with no arguments. I used <code>--prefix=/usr</code> to change from the default of<code>/usr/local</code>. On your system you may want to add <code>--enable-64bit</code> or <code>--enable-threads</code>, depending on your configuration and expected load.</p>
<p>Run a quick <code>make &amp;&amp; make install</code> and you&#8217;re done.</p>
<h3>Running Memcached</h3>
<p>You can run Memcached from the command line but sticking the <code>-d</code> parameter to run as a daemon. If you&#8217;re still root, you&#8217;ll need to add <code>-u<em>nobody</em></code>, where &#8220;nobody&#8221; is some unprivileged user. And that&#8217;s it. Memcached is up and running on your server and ready to connect.</p>
<p>If you&#8217;re on a system with chkconfig, I&#8217;ve put together a <a href="http://coffeeonthekeyboard.com/wp-content/uploads/2008/05/memcache-chkconfig.zip" title="Memcached Chkconfig Scripts">simple chkconfig script</a> for it. The zip file contains two files, <code>etc/rc.d/init.d/memcached</code> and <code>etc/sysconfig/memcached</code>. Copy them to those locations, <code>chmod +x /etc/rc.d/init.d/memcached</code> and then run <code>chkconfig --add memcached</code>, and <code>chkconfig memcached on</code> to run Memcached when the server starts. You can type <code>service memcached start</code> to get it up and running.</p>
<p>Typing <code>memcached -h</code> will show you all the options, including which ports and IP addresses to listen on, or which socket to use, how much memory to allocate, and others. You can add any of these command line options to the <code>$OPTIONS</code> variable in the <code>/etc/sysconfig/memcached</code> file to set the default options for the Memcached service.</p>
<h3>Using Memcached (Finally!)</h3>
<p>Memcached is installed and running. Now what? Well it sort of depends on your language—there are Memcached bindings for Perl, PHP, Ruby, Java, Python, C, C#, Lua, and even Postgres and MySQL—and your program. I&#8217;m not going to go through the specific implementation, but here&#8217;s the basic idea. (In PHP. Ok, so I lied about that specific-implementation thing.)</p>
<p>Let&#8217;s say our goal is to reduce database load. Then we want to try to preempt as many SELECT queries as we can.</p>
<p>If your original code was like this: (Please! Be safe about SQL-injection.)</p>
<blockquote>
<pre>// What post do we want?
$id = get_current_id();

// Query the database
$query = "SELECT * FROM posts WHERE id = '$id';"
$result = $db-&gt;query($query);

// Now we have the post data
$post = $result-&gt;fetch_assoc();</pre>
</blockquote>
<p>What we&#8217;re doing is getting an ID, possibly from a user, then getting the associated table row and returning it. Now to speed that up with Memcached:</p>
<blockquote>
<pre>// Create a new Memcache object
$m = new Memcache;
$m-&gt;<a href="http://s.hort.cc/D">connect</a>('localhost');

// Check Memcache for the data, first
if ( !$post = $m-&gt;get("post:$id") ) {
  // Not in the cache, get from the database
  $query = "SELECT * FROM posts WHERE id = '$id';";
  $result = $db-&gt;query($query);

  // Get the post data
  $post = $result-&gt;fetch_assoc();

  // If we expect this data to be used again soon,
  // we can store it in the cache
  $m-&gt;set("post:$id", $post);
}</pre>
</blockquote>
<p>There we have all the basics. The string <code>"post:$id"</code> is the Memcached key. The post data is serialized and stored (with <a href="http://s.hort.cc/E">Memcache::set</a>) as a key-value pair. If it&#8217;s in the cache, which we can check with <a href="http://s.hort.cc/F">Memcache::get</a> (unless the stored value was boolean <code>false</code>, then it gets confusing) then we don&#8217;t need to waste a database query.</p>
<p>If you expect data to be used as soon as it&#8217;s created, you can do your database <code>INSERT</code> statements and then store the same data in the cache immediately. (Or <a href="http://s.hort.cc/G">Memcache::replace</a>, whichever is necessary.)</p>
<h3>So, what?</h3>
<p>To be fair, my Memcached example made the code much longer, and required instantiating another object, another TCP connection&#8230; What&#8217;s the payoff?</p>
<p>Memcached was written to improve performance over at LiveJournal when they hit the 20+ million page view/day mark. Imagine that database call was in a loop, or if, instead of serializing one post, we built an array of all the posts from one user, and stored that. You can quickly see how many database queries we eliminate.</p>
<p>For fun, I ran a test that generated a random number, then tried to pull the associated row out of a database. (I only generated numbers for which I knew there was a row.) I iterated over this 3,000 times and did 10 trials each.</p>
<p>In PHP with a MySQL database, the Memcached version was around 60% faster, averaging 0.315 seconds vs. 0.820 seconds without Memcached.</p>
<h3>But Wait! There&#8217;s More</h3>
<p>Since Memcached was designed for a site that already existed on dozens of servers, it&#8217;s based on the idea that you&#8217;d run Memcached on all your web servers, and then treat them like a pool. You can connect to several servers simultaneously to spread the Memcaching around. Data gets hashed to a particular server and, if it&#8217;s available on any of them, gets pulled back.</p>
<p>Memcached can also compress data on the fly with zlib, so if you did plan on storing the last 20 posts of every user, you wouldn&#8217;t be out quite so much space.</p>
<p>Finally, Memcached will keep adding data until it hits its memory limit, and which point it drops the Least Recently Used stuff to make room. So even though you can set data not to expire, you can&#8217;t trust that it will be in the cache forever.</p>
<p>For sites that rely on database reads, Memcached can help a lot. If you&#8217;re site depends more on writes or updates, it will probably do very little, or even cause unnecessary overhead.</p>
<p>But since most data-driven sites are significantly bigger readers than writers, Memcached is a great way to improve response time and quality of service, and to reduce load on those databases for when you really do need to read or write to it.</p>
<h3>Do You Memcached?</h3>
<p>So, do you use Memcached? How? Does it speed up your service or have no noticeable effect?</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/better-living-through-memcached-85/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to: Upgrade or Recompile PHP on RHEL5 (Outdated)</title>
		<link>http://coffeeonthekeyboard.com/how-to-upgrade-or-recompile-php-on-rhel5-59/</link>
		<comments>http://coffeeonthekeyboard.com/how-to-upgrade-or-recompile-php-on-rhel5-59/#comments</comments>
		<pubDate>Sat, 03 Nov 2007 17:00:00 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[recompile]]></category>
		<category><![CDATA[red hat]]></category>
		<category><![CDATA[servers]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/how-to-upgrade-or-recompile-php-on-rhel5-59/</guid>
		<description><![CDATA[Update: This post is nearly two years old, and this is not how I would recommend upgrading PHP on RHEL, yet it continues to get traffic. If I can get my hands on a copy of RHEL, I&#8217;ll update this (or I might try using Fedora just to compare). Upgrading PHP on RHEL 5 is [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update: </strong><em>This post is nearly two years old, and this is <strong>not</strong> how I would recommend upgrading PHP on RHEL, yet it continues to get traffic. If I can get my hands on a copy of RHEL, I&#8217;ll update this (or I might try using Fedora just to compare).</em></p>
<p>Upgrading PHP on RHEL 5 is difficult. Having done it on several servers, I&#8217;ve gotten it down to a 15 to 20 step process. It takes a while, but it&#8217;s straightforward. I thought I&#8217;d share, because help was sparse and noncontiguous at best.</p>
<p class="image right"><img src="/blog/images/rhel.png" alt="RedHat Enterprise Linux: Hard to upgrade PHP." width="96" height="31" /></p>
<p>RedHat Enterprise Linux 5 comes with PHP 5.1.6 and, as of this writing, this is the highest version available on yum. If you want to upgrade to 5.2.4, or even recompile 5.1.6 with a custom configuration, you&#8217;ll need to resolve several dependencies, first.</p>
<p class="note">Unless otherwise specified, whenever I run <code>./configure</code>, I always include <code>--enable-shared</code> and <code>--enable-static</code>.</p>
<p>The first step is to make sure you have a working APXS script installed. None of the servers on which I&#8217;ve done this had it. I installed Apache 2.2.4 over the default install, since it was the latest version. Be sure to enable APXS with <code>--enable-so</code>. Be careful configuring Apache, as it likes to install itself in <code>/usr/local/apache2/</code> instead of <code>/etc/httpd/</code>, which you may prefer.</p>
<p>Now we start resolving the dependencies. I&#8217;d start with <strong>libtool</strong> and <strong>libiconv</strong>. The former you should be able to install via yum. The latter you may have to download, and after you configure it, from the source directory copy <code>m4/iconv.m4</code> to <code>/usr/local/share/aclocal/iconv.m4</code>.</p>
<p>Use yum to make sure <code>mysql-devel</code> is installed, you&#8217;ll need it to link to mysql.</p>
<p>Then I&#8217;d do the image manipulation software, since it&#8217;s fairly easy. Use yum to install <code>libjpeg</code>, <code>libpng</code> and <code>freetype</code>. You can then use yum to make sure both <code>gd</code> and <code>gd-devel</code> are installed.</p>
<p>I installed <code>libmcrypt</code>, <code>libmhash</code>, and <code>ming</code> at this point. I&#8217;d say it&#8217;s a good time to get any of these more particular dependencies out of the way. I also installed Tidy, which you need to check out from their CVS repository. You can run <code>build/gnuauto/setup.sh</code> from the Tidy source directory to create the autoconf files.</p>
<p>Now we get to the crux of the matter: configuring PHP. All the major dependencies should have been taken care of. If you have other PHP options you&#8217;ll need, make sure those prerequisites are installed, as well. Run the configure script in the PHP source directory with everything you need enabled. I find it helpful to create a script like <code>php.config</code> with the following format:</p>
<pre>'./configure' \
'--with-cgi' \
'--with-fastcgi' \
'--with-gd' \
...
'--with-xml' \
"$@"</pre>
<p class="note">You need to include the slashes <code>\</code> at the end of every line. The last line, <code>"$@"</code> makes the script output the output of <code>configure</code>.</p>
<p>If you get an error running <code>make</code>, you may need to edit your <code>Makefile</code>. Find the <code>EXTRA_LIBS</code> section (in vi/vim, type <code>&lt;ctrl-c&gt; /EXTRA_LIBS &lt;return&gt;</code>) and add <code>-liconv</code> to the end of the line. Then try <code>make clean &amp;&amp; make</code> and it should work.</p>
<p>You may or may not have to edit your <code>httpd.conf</code>, after running <code>make install</code> from the PHP source directory, to add the <code>AddType</code> or <code>AddHandler</code> directive for PHP.</p>
<p>That should be it. You can install extensions via PECL or Pear and everything should run. Save the source directory and your <code>php.config</code> (or <code>config.nice</code>) file, and you&#8217;ll be able to recompile at any time, in case you forgot something. (I, for example, forgot to add <code>--with-mysql</code> the first time!)</p>
<p>Let me know if you run into other problems. Most can be solved by typing <code>yum install ###-devel</code> to resolve a dependency, but if not, I&#8217;ve done this enough to be of some help.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/how-to-upgrade-or-recompile-php-on-rhel5-59/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MySQL Subqueries</title>
		<link>http://coffeeonthekeyboard.com/mysql-subqueries-48/</link>
		<comments>http://coffeeonthekeyboard.com/mysql-subqueries-48/#comments</comments>
		<pubDate>Mon, 06 Aug 2007 01:31:00 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[subquery]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/mysql-subqueries-48/</guid>
		<description><![CDATA[I often find it difficult to find tips and advice for doing relatively simple things in things like MySQL, Ruby, Python, etc. So, starting with this post, I will help fill that niche. Today&#8217;s topic is Using Subqueries to Simplify your SQL Queries. For this article, I&#8217;m using PHP and MySQL for examples. There are [...]]]></description>
			<content:encoded><![CDATA[<p>I often find it difficult to find tips and advice for doing relatively simple things in things like MySQL, Ruby, Python, etc. So, starting with this post, I will help fill that niche. Today&#8217;s topic is <strong>Using Subqueries to Simplify your SQL Queries.</strong></p>
<p class="note" style="font-style: italic; font-size: 90%; color: #999999">For this article, I&#8217;m using PHP and MySQL for examples. There are slightly different implementations of SQL in the various database engines, but this is one thing they all have in common.</p>
<p>SQL is called &#8220;<strong>s</strong>tructured <strong>q</strong>uery <strong>l</strong>anguage&#8221; because it allows subqueries to make complex queries easier and faster. The idea of a subquery is simple: have the database perform one query and insert it into another.</p>
<p>There are dozens of useful ways of using subqueries, but I will concentrate on two: subqueries in the <em>select expression</em> and subqueries in the <em>where clause</em>.</p>
<h3>Security Concerns</h3>
<p>In most web programming languages, the interface between the script and the database only allows one query per access for security reasons: an injection attack could input something like <code>'; DELETE * FROM users;</code> and do some serious damage to a website. Imagine your SQL query to login looked something like:</p>
<blockquote><p><code>SELECT * FROM users WHERE user_name = '$username' AND password = '$password';</code></p></blockquote>
<p>If you are not checking and cleaning the input appropriately, someone could type the snippet above into your login form and, if multiple queries were allowed, MySQL would execute the following:</p>
<blockquote><p><code>SELECT * FROM users WHERE user_name = ''; DELETE * FROM users; AND password='';</code></p></blockquote>
<p>Since the empty string wouldn&#8217;t match any rows (hopefully), the first query would be discarded. The second query, the <code>DELETE</code> statement, would run, terminating at the second semicolon. Since the third piece of code is nonsense, MySQL would throw it out with an error.</p>
<p>To solve this problem, languages like PHP cause MySQL to issue an error any time there is more text (except comments) after the line terminator, usually the semicolon. The downside is that situations arise where you need to run multiple queries. The result is either often either a godawfully complicated statement with multiple <code>JOIN</code>s, or running several queries, each of which requires communication with your database server and can slow down your applications.</p>
<p>In the examples below, I&#8217;ll pretend we&#8217;re building a forum that has four tables:</p>
<ul>
<li><code>users</code> with primary key <code>user_id</code></li>
<li><code>forums</code>, a list of all the boards, with primary key <code>forum_id</code></li>
<li><code>threads</code> which links each thread to a forum with <code>forum_id</code> and has primary key <code>thread_id</code></li>
<li><code>posts</code> which links each post to a thread with <code>thread_id</code> and has primary key <code>post_id</code></li>
</ul>
<h3>Subqueries in Select Expressions</h3>
<p>One way to speed up your queries again is to use subqueries. Subqueries are full SQL queries nested within another query. For example:</p>
<blockquote><p><code>SELECT (SELECT * FROM t1);</code></p></blockquote>
<p>Obviously it&#8217;s a pretty simple example. Notice the parentheses. Subqueries must always be in parentheses, even if they are inside a function, like:</p>
<blockquote><p><code>SELECT MAX((SELECT salary FROM employees));</code></p></blockquote>
<p>Let&#8217;s get to work on our forum. Say that while reading all the threads of a forum you&#8217;d like to have both the number of threads and the number of posts in the forum. One way is to run two separate queries:</p>
<blockquote><p><code>SELECT COUNT(*) AS threads FROM threads WHERE forum_id='1';<br />
SELECT COUNT(*) AS posts FROM posts LEFT JOIN threads USING(thread_id) WHERE forum_id='1';</code></p></blockquote>
<p>That might not be so bad if your SQL server is <code>localhost</code>, but more and more hosts are running dedicated SQL servers, meaning that every query has to run across the internet, be processed, and run back, slowing down your application. But we can run this in one query with two subqueries:</p>
<blockquote><p><code>SELECT<br />
(SELECT COUNT(*) FROM threads WHERE forum_id='1') AS threads,<br />
(SELECT COUNT(*) FROM posts LEFT JOIN threads USING(thread_id) WHERE forum_id='1') AS posts;</code></p></blockquote>
<p>We can add the above to our query to get the name of the forum and its description, so we can further decrease the number of trips to the database:</p>
<blockquote><p><code>SELECT<br />
(SELECT COUNT(*) FROM threads WHERE threads.forum_id=forums.forum_id) AS threads,<br />
(SELECT COUNT(*) FROM posts LEFT JOIN threads USING(thread_id) WHERE threads.forum_id=forums.forum_id) AS posts,<br />
forum_name,<br />
forum_description<br />
FROM forums WHERE forum_id='1';</code></p></blockquote>
<p>Notice that we also changed the <code>WHERE</code> clauses to match whatever forum ID we put into the &#8220;<em>outer query</em>&#8220;.</p>
<h3>Subqueries in Where Clauses</h3>
<p>Another simple and useful way to use a subquery is in a <code>WHERE</code> clause. Here you must be careful to match the <code>WHERE</code> syntax and the type of data returned by the subquery. For example, in <code>WHERE user_name = (...)</code>, the subquery (<code>(...)</code>) must return a single value, while in <code>WHERE post_date IN (...)</code>, the subquery can return a list.</p>
<p>In our forum, we might want to search for all posts by a specific user, but we don&#8217;t want our visitors to need to know the user ID—or perhaps we want a more descriptive URL, like <code>search.php?user=USER_NAME</code> instead of <code>search.php?user=#ID#</code>. But in our forum, to be efficient, we link posts to their author by the <code>user_id</code> column.</p>
<p>One way to do this is to run a query to find the ID then run another query to find the posts. Another way in this particular case is to use a <code>JOIN</code> statement. But yet another way is to do this:</p>
<blockquote><p><code>SELECT * FROM posts WHERE user_id = (SELECT user_id FROM users WHERE user_name = 'foo');</code></p></blockquote>
<p>In the case above, a <code>JOIN</code> would also get us the information we want, but in some cases this isn&#8217;t true, for example:</p>
<blockquote><p><code>SELECT column1 FROM t1<br />
WHERE column1 = (SELECT MAX(column2) FROM t2);</code></p></blockquote>
<p>When you need to <code>COUNT</code> or otherwise aggregate one column, you&#8217;ll need to use a subquery instead of a <code>JOIN</code>, as well.</p>
<h3>Summary</h3>
<p>This article only scratched the surface of subqueries. Subqueries can be nested, they can appear in other places and do other things, and they can make your SQL more readable, among others. I don&#8217;t claim that the SQL statements above are the world&#8217;s most efficient or best way to do things—if you know a better way, let me know! I just want to give an introduction to subqueries, a very basic part of SQL that few people I&#8217;ve met seem to understand.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/mysql-subqueries-48/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CSS: Good; Everything Else: Bad</title>
		<link>http://coffeeonthekeyboard.com/css-good-everything-else-bad-33/</link>
		<comments>http://coffeeonthekeyboard.com/css-good-everything-else-bad-33/#comments</comments>
		<pubDate>Sat, 12 Aug 2006 00:44:00 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/css-good-everything-else-bad-33/</guid>
		<description><![CDATA[Images, flash, frames. These are the &#8220;traditional&#8221; methods for making a web site &#8220;more interesting&#8221; or &#8220;better looking.&#8221; But these hold-overs from the AOL era are the bane of bandwidth, text-only browsers, and non-visual users. HTML, of course, was originally written to define the structure of a web page, never it&#8217;s design. In essence, HTML [...]]]></description>
			<content:encoded><![CDATA[<p>Images, flash, frames. These are the &#8220;traditional&#8221; methods for making a web site &#8220;more interesting&#8221; or &#8220;better looking.&#8221; But these hold-overs from the AOL era are the bane of bandwidth, text-only browsers, and non-visual users.</p>
<p>HTML, of course, was originally written to define the <span style="font-style: italic">structure</span> of a web page, never it&#8217;s design. In essence, HTML was intended to be much like XML today. But, when HTML was created, there were no style-sheets, so HTML was forced to include some design information, like &lt;font&gt; tags and the <tt>bgcolor</tt> attribute. Developers quickly turned to images, JavaScript, frames, and Flash to make their lives easier, but in the process made everyone else&#8217;s life harder.</p>
<p>Images and Flash will both suck bandwidth, so why would you use them to display text or a navigation bar? Save images and Flash for what they&#8217;re supposed to be: pictures and animations. Frames reek havoc on text-only browsers and screen-readers (hence the rarely-used &lt;noframes&gt; tag) and have been considered blase web-design for years.</p>
<p>So how can you save bandwidth, insure accessibility, and still get all the effects you want? <abbr title="Cascading Style Sheets.">CSS</abbr>. Let&#8217;s go over a few of the quick-and-easy ways to use CSS to replace the bandwidth-heavy, inaccessible design you&#8217;re using now:</p>
<p><span style="font-weight: bold">1) Frames: Fixed Sidebars</span><br />
Perhaps the most common use of frames was the sidebar, a window on the left (or right) that contained anything from helpful information to your site&#8217;s navigation, appeared on every page, and didn&#8217;t scroll with the rest of the site.</p>
<p>If you want to do the same thing, use the CSS &#8220;position: fixed&#8221; definition. For instance:</p>
<pre>#sidebar {
position: fixed;
top: 0;
left: 0;
width: 160px;
height: 100%;
background: #00f;
}</pre>
<p>This will make a non-scrolling, 160-pixel wide sidebar on the left of the screen. (You could always use &#8220;right&#8221; and &#8220;bottom,&#8221; too.) Now, in your HTML file, create a &lt;div&gt; with the <tt>id="sidebar"</tt> attribute:</p>
<pre>&lt;div id="sidebar"&gt;
...all your links go here...
&lt;/div&gt;</pre>
<p>You can put this anywhere in the HTML source, and it will appear in the correct place. In a good screen-reader, if you put this toward the bottom of the HTML source (for instance, after all the content of the page) then the user would hear the content before having to hear the list of links again.</p>
<p><span style="font-weight: bold">2) Images: Positioning Text</span><br />
This is really just poor web-design. Unless it&#8217;s desperately important that you use a particular,  rare font, you should never use images to display text. If it&#8217;s important that the text appear a certain way or in a certain position, make use of the box-model and nested &lt;div&gt;s. For example, let&#8217;s say you wanted a 480-pixel wide layout, regardless of the users&#8217; screen resolution, with a right gutter and a title and slogan in the top-left. You might do something like:</p>
<pre>#main {
width: 480px;
height: 100%;
margin: 0 auto;
padding: 0;
position: relative;
top:0;
left:0;
}
#gutter {
width: 120px;
height: 100%;
margin: 0;
padding: 0;
border-left: 1px solid #000;
position: absolute;
top: 0;
right: 0;
background: #2c2;
color: #fff;
}
#header {
width: 360px;
margin: 0;
padding: 6px;
position: relative;
top: 0;
left: 0;
font-family: Tahoma, Arial, san-serif;
font-size: 140%;
text-align: center;
}</pre>
<p>With the corresponding HTML:</p>
<pre>&lt;div id="main"&gt;
&lt;div id="gutter"&gt;
...gutter code here...
&lt;/div&gt;
&lt;div id="header"&gt;
&lt;p&gt;Page Title&lt;/p&gt;
&lt;p&gt;Page Slogan&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</pre>
<p>Which gives something like (borders added to show box model):</p>
<p><img src="http://jamessocol.com/images/screenshot.png" /></p>
<p>Now, of course, with just a little editing of the CSS file (and none of the HTML) you can move the gutter, change the background, change the page width, change the font, and it&#8217;s all in text-format, that will display correctly to text-only or visually-impaired browsers, and save huge percentages of bandwidth.</p>
<p><span style="font-weight: bold">3) Flash: Cool Navigation Bars</span><br />
This gets a little more complicated. In general, it&#8217;s hard to define the box around &lt;a&gt; tags, so you&#8217;ll probably want to do something like this:</p>
<pre>#nav
{   margin: 4px auto 0 auto;
 position: relative;
 top: 0;
 left: 0;
}
#nav ul
{   display: inline;
 list-style-type: none;
}
#nav li
{   display: inline;
 border: 1px solid #000;
 padding: 2px 4px 0 4px;
 margin: auto 4px 0 4px;
}
#nav li.here
{   border-bottom: 1px solid #FFF;
}
#nav li:HOVER
{   border-bottom: 1px solid #FFF;
 font-weight: bold;
}</pre>
<p>Now in each &lt;li&gt; tag you&#8217;ll make a link to the page you want. This particular set of code gives you a horizontal list. I use a version of this on my <a href="http://projects.jamessocol.com" title="Projects page.">projects page</a>, so you can see it in action. If you remove the <tt>display: inline</tt> parts, you&#8217;ll get the vertical list you need for a column. Of course, the margin, padding, and all the colors can be customized however you want, to make it look right. (I got this from the <a href="http://www.alistapart.com">AListApart</a> article &#8220;<a href="http://www.alistapart.com/articles/taminglists/">Taming Lists</a>&#8220;, which you should read for more information.)</p>
<p><span style="font-weight: bold">So there you go&#8230;</span><br />
It&#8217;s not all the info you&#8217;ll ever need, but it solves three of the most heinous wastes of bandwidth I&#8217;ve seen on the web, as well as all the problems people have with accessibility. These methods can both look great, and be completely usable by everyone, something Flash, frames, and images can&#8217;t.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/css-good-everything-else-bad-33/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

