{"id":2156,"date":"2010-03-11T09:10:09","date_gmt":"2010-03-11T07:10:09","guid":{"rendered":"http:\/\/code.openark.org\/blog\/?p=2156"},"modified":"2010-03-11T14:13:51","modified_gmt":"2010-03-11T12:13:51","slug":"proper-sql-table-alias-use-conventions","status":"publish","type":"post","link":"https:\/\/code.openark.org\/blog\/mysql\/proper-sql-table-alias-use-conventions","title":{"rendered":"Proper SQL table alias use conventions"},"content":{"rendered":"<p>After seeing quite some SQL statements over the years, something is bugging me: there is no consistent convention as for how to write an SQL query.<\/p>\n<p>I&#8217;m going to leave formatting, upper\/lower-case issues aside, and discuss a small part of the SQL syntax: table aliases. Looking at three different queries, I will describe what I find to be problematic table alias use.<\/p>\n<p>Using the <a href=\"http:\/\/dev.mysql.com\/doc\/sakila\/en\/sakila.html\">sakila<\/a> database, take a look at the following queries:<!--more--><\/p>\n<h4>Query #1<\/h4>\n<blockquote>\n<pre><strong>SELECT<\/strong>\r\n R.rental_date, C.customer_id, C.first_name, C.last_name\r\n<strong>FROM<\/strong>\r\n rental R\r\n <strong>JOIN<\/strong> customer C <strong>USING<\/strong> (customer_id)\r\n<strong>WHERE<\/strong>\r\n R.rental_date &gt;= DATE('2005-10-01')\r\n <strong>AND<\/strong> C.store_id=1;\r\n<\/pre>\n<\/blockquote>\n<p>The above looks for film rentals done in a specific store (store #<strong>1<\/strong>), as of Oct. 1st, 2005.<\/p>\n<h4>Query #2<\/h4>\n<blockquote>\n<pre><strong>SELECT<\/strong>\r\n F.title, C.name\r\n<strong>FROM<\/strong>\r\n film <strong>AS<\/strong> F\r\n <strong>JOIN<\/strong> film_category <strong>AS<\/strong> S <strong>ON<\/strong> (F.film_id = S.film_id)\r\n <strong>JOIN<\/strong> category <strong>AS<\/strong> C <strong>ON<\/strong> (S.category_id = C.category_id)\r\n<strong>WHERE<\/strong> F.length &gt; 180;<\/pre>\n<\/blockquote>\n<p>The above lists the title and category for all films longer than three hours.<\/p>\n<h4>Query #3<\/h4>\n<blockquote>\n<pre><strong>SELECT<\/strong> c.customer_id, c.last_name\r\n<strong>FROM<\/strong>\r\n  customer c\r\n  <strong>INNER JOIN<\/strong> address a ON (c.address_id = a.address_id)\r\n  <strong>INNER JOIN<\/strong> (\r\n    <strong>SELECT<\/strong>\r\n      c.city_id\r\n    <strong>FROM<\/strong>\r\n      city AS c\r\n      <strong>JOIN<\/strong> country s <strong>ON<\/strong> (c.country_id = s.country_id)\r\n    <strong>WHERE<\/strong>\r\n      s.country <strong>LIKE<\/strong> 'F%'\r\n  ) s1 <strong>USING<\/strong> (city_id)\r\n<strong>WHERE<\/strong>\r\n  create_date &gt;= DATE('2005-10-01');\r\n<\/pre>\n<\/blockquote>\n<p>The above lists customers created as of Oct. 1st, 2005, and who live in countries starting with an &#8216;F&#8217;. The query could be solved without a subquery, but there&#8217;s a good reason why I made it so.<\/p>\n<h4>The problems<\/h4>\n<p>I used very different conventions on any one of the queries, and sometimes within each query. And it&#8217;s common that I see the same on a customer&#8217;s site, what with having many programmers do the SQL coding. Again, I will only discuss the table aliases conventions. I&#8217;ll leaver the rest to the reader.<\/p>\n<p>Here&#8217;s where I see problems:<\/p>\n<ul>\n<li>Query <strong>#1<\/strong>: In itself, it looks fine. <strong>Rental<\/strong> turns to <strong>R<\/strong>, <strong>Customer<\/strong> turns to <strong>C<\/strong>. I will comment on this slightly later on when I provide my full opinion.<\/li>\n<li>Query <strong>#2<\/strong>: So <strong>film<\/strong> turns to <strong>F<\/strong>, <strong>category<\/strong> turns to <strong>C<\/strong>. What should <strong>film_category<\/strong> turn into? <em>Out of letters?<\/em> Let&#8217;s just go for <strong>S<\/strong>, shall we? But <strong>S<\/strong> has nothing do with <strong>film_category<\/strong>. Yet it&#8217;s so commonly seen.<\/li>\n<li>Query <strong>#2<\/strong>: We&#8217;re using the <strong>AS<\/strong> keyword now. We didn&#8217;t use it before.<\/li>\n<li>Queries <strong>#1<\/strong>, <strong>#2<\/strong>: Hold on. Wasn&#8217;t <strong>C<\/strong> taken for <strong>customer<\/strong> in Query <strong>#1<\/strong>? Now, in Query <strong>#2<\/strong> it stands for <strong>category<\/strong>? I&#8217;m beginning to get confused.<\/li>\n<li>Query <strong>#3<\/strong>: Now aliases are lower case; I was just getting used to them being upper case.<\/li>\n<li>Query <strong>#3<\/strong>: But, hey, <strong>c<\/strong> is back to <strong>customer<\/strong>!<\/li>\n<li>Query <strong>#3<\/strong>: Or, is it? Take a look at the subquery. Theres another <strong>c<\/strong> in there! This time it&#8217;s <strong>city<\/strong>! And it&#8217;s perfectly valid syntax. We actually have two identical aliases in the same query.<\/li>\n<li>Query <strong>#3<\/strong>: If I could, I would name country with <strong>c<\/strong> as well. But I can&#8217;t. So why not throw in <strong>s<\/strong> again?<\/li>\n<li>Query <strong>#3<\/strong>: and now I don&#8217;t even bother using the alias when accessing the <strong>create_date<\/strong>. Well, there&#8217;s no such column in any of the other tables!<\/li>\n<\/ul>\n<h4>Proper conventions<\/h4>\n<p>What I find so disturbing is that whenever I read a complex query, I need to go back and forth, back and forth between table aliases (found everywhere in the query) and their declaration point. Such irregularities make the queries difficult to read.<\/p>\n<p>Any of the above issues could be justified. But I wish to make some suggestions:<\/p>\n<ul>\n<li>Decide whether you&#8217;re going for upper or lower case.<\/li>\n<li>Do not use the same alias twice in your query, even if it&#8217;s valid.<\/li>\n<li>Aliases do not have to be single character. <strong>film_category<\/strong> may just as well be <strong>FC<\/strong>.<\/li>\n<li>Do not alias something that is hard to interpret. <strong>s<\/strong> does not stand for <strong>country<\/strong>.<\/li>\n<li>Think ahead: use same aliases throughout all your queries, as far as you can. If uniqueness is a problem, make for longer aliases. Use <strong>cust<\/strong> instead of <strong>c<\/strong>.<\/li>\n<\/ul>\n<p>The above should make for more organized and readable SQL code. Remember: what one programmer finds as a very intuitive alias, is unintuitive to another!<\/p>\n<h4>My own convention<\/h4>\n<p>Simple: I <em>only use aliases<\/em> when using self joins. I am aware that queries are much longer what with long table names. I go farther than that: I prefer fully qualifying questionable columns throughout the query. Yes, it makes the query even longer.<\/p>\n<p>I know this does not appeal to many. But there&#8217;s no confusion. And it&#8217;s easily searchable. And it&#8217;s consistent. And if properly formatted, as in the above queries, is well readable.<\/p>\n<p>Now please join me in asking Oracle if they can add multi-line Strings for java, as there are for python.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After seeing quite some SQL statements over the years, something is bugging me: there is no consistent convention as for how to write an SQL query. I&#8217;m going to leave formatting, upper\/lower-case issues aside, and discuss a small part of the SQL syntax: table aliases. Looking at three different queries, I will describe what I [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2}},"categories":[5],"tags":[6,51,31,21,20],"class_list":["post-2156","post","type-post","status-publish","format-standard","hentry","category-mysql","tag-java","tag-opinions","tag-python","tag-sql","tag-syntax"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2bZZp-yM","_links":{"self":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/2156","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/comments?post=2156"}],"version-history":[{"count":16,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/2156\/revisions"}],"predecessor-version":[{"id":2170,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/2156\/revisions\/2170"}],"wp:attachment":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/media?parent=2156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/categories?post=2156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/tags?post=2156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}