{"id":399,"date":"2008-03-31T19:47:00","date_gmt":"2008-03-31T19:47:00","guid":{"rendered":"\/blogs\/conor\/post\/How-to-write-non-JOIN-WHERE-clauses.aspx"},"modified":"2008-03-31T19:47:00","modified_gmt":"2008-03-31T19:47:00","slug":"how-to-write-non-join-where-clauses","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/","title":{"rendered":"How to write non-JOIN WHERE clauses"},"content":{"rendered":"<p>Based on my previous post describing the differences between ANSI-89 and ANSI-92+ join syntaxes and recommendations, I had a follow-up question in a comment which was (paraphrased)<\/p>\n<p>What do I do with non-join WHERE clauses &#8211; how should I write those?<\/p>\n<p>Example:<\/p>\n<p class=\"MsoPlainText\">\n<pre><span style=\"color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;\"><span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">SELECT<\/span> p.FirstName + <span style=\"color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;\">' works in '<\/span> + d.DepartmentName <span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">AS<\/span> <span style=\"color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;\">'Who Works Where'<\/span>\r\n<span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">FROM<\/span> Person <span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">AS<\/span> p\r\n<span style=\"color: Silver; background-color: transparent; font-family: Courier New; font-size: 11px;\">JOIN<\/span> Department <span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">AS<\/span> d\r\n<span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">ON<\/span> p.DepartmentID = d.DepartmentID\r\n  <span style=\"color: Silver; background-color: transparent; font-family: Courier New; font-size: 11px;\">AND<\/span> p.JobType = <span style=\"color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;\">'Salaried'<\/span>\r\n<\/span><\/pre>\n<p>(so, the question is about the filter condition on p.JobType).<\/p>\n<p>Answer: it doesn&#8217;t generally matter, but I&#8217;d recommend that you put it in the WHERE clause for readability.<\/p>\n<p>I&#8217;ll explain the why now.&nbsp; A little background first:<\/p>\n<p>In SQL Server (actually all QPs of any note), the SQL string is converted into an operator tree and then there&#8217;s a lot of magic to rewrite that query tree into alternative forms of the query.&nbsp; While some people think of this as &#8220;if I try different syntaxes, the query may execute faster&#8221;, the optimizer is actually doing something at a much deeper level &#8211; it is essentially rewriting the tree using a series of rules about equivalences.&nbsp; It&#8217;s a lot more like doing a math proof than trying different syntaxes &#8211; it deals with associativity, commutivity, etc. (Conor bats cobwebs out of people&#8217;s heads- yes, you guys did this stuff in school).&nbsp; It&#8217;s a big set theory algebra machine.&nbsp; So, you put in a tree repesenting the syntax at one end and get a query plan out the other side.<\/p>\n<p>So, I&#8217;ll ask the question from a slightly different perspective and answer that too to help explain the &#8220;why&#8221;:<\/p>\n<p>&#8220;Does putting filters in the join condition of an inner join impact the plan choice from the optimizer?&#8221;.<\/p>\n<p>Answer: no &#8211; at least not in most cases.&nbsp; <\/p>\n<p>When the SQL Server Optimizer starts working on this query, it will do<br \/>\na number of things very early in the optimization process. One thing is called &#8220;simplification&#8221;, and most of you can guess what will happen there.&nbsp; One core task in simplication is &#8220;predicate pushdown&#8221;, where the query is rewritten to push the filter conditions in WHERE clauses towards the tables on which the predicates are defined.&nbsp; This mostly enables index matching later in optimization.&nbsp; It also enables computed column matching.<\/p>\n<p>So, these predicates are pushed down in both cases.&nbsp; You lose a lot in query readability by trying this form of rewrite for very little gain.<\/p>\n<p>There is one case where I&#8217;d consider doing this, but it really requires that you have uber knowledge of the QP.&nbsp; However, this seems like a good challenge, so I&#8217;ll explain the situation and let you guys write in if you can find an example of it:<\/p>\n<p>You know that the QP uses relational algebra equivalence rules to rewrite a query tree (so A join B is equivalent to B join A, filter .a(a join b) == (select * from a where filter.a) join b, etc.<\/p>\n<p>One could imagine that some of the fancier operators may not fit as easily into the relational algebra rewrite rules.&nbsp; (Or, they are just so complex that the cost of trying such rewrites outweighs the benefit).<\/p>\n<p>Can you find operators where (filter (OPERATOR (SCAN TABLE)) is not equivalent to (OPERATOR (filter (SCAN TABLE))?&nbsp; <\/p>\n<p>Obviously inner join is a bad place to start.&nbsp; I&#8217;ll throw out some not-so-random areas for you to try:<br \/>* updates<br \/>* xml column manipulations<br \/>* SELECT list items on objects that change semantics based on how many times they are executed in a query (rand()?&nbsp; think functions)<br \/>* play with group by (this one is tricky)<br \/>* OVER clause?<br \/>* UNION\/UNION ALL, INTERSECT, &#8230;<\/p>\n<p>So, there are some cases where the QP will do these rewrites, and there are some places where it can&#8217;t\/won&#8217;t (or at least doesn&#8217;t do it always).&nbsp; In a few of these cases, the intent of the query can be preserved by manually rewriting the query to push the predicate &#8220;down&#8221; the query tree towards the source tables.&nbsp; However, I would not recommend this unless you really know what you are doing &#8211; the query rewrite needs to be equivalent or else you may not get the right results back from your query!<\/p>\n<p>Bottom line &#8211; I think that the query is far more readable with non-join predicates in the WHERE clause.&nbsp; Whenever I try to optimize queries, I usually push them into this format so that I can wrap my head around what the query is trying to accomplish.<\/p>\n<p>Happy querying!<\/p>\n<p>Conor<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Based on my previous post describing the differences between ANSI-89 and ANSI-92+ join syntaxes and recommendations, I had a follow-up question in a comment which was (paraphrased) What do I do with non-join WHERE clauses &#8211; how should I write those? Example: SELECT p.FirstName + &#8216; works in &#8216; + d.DepartmentName AS &#8216;Who Works Where&#8217; [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-399","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.9.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to write non-JOIN WHERE clauses - Conor Cunningham<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to write non-JOIN WHERE clauses - Conor Cunningham\" \/>\n<meta property=\"og:description\" content=\"Based on my previous post describing the differences between ANSI-89 and ANSI-92+ join syntaxes and recommendations, I had a follow-up question in a comment which was (paraphrased) What do I do with non-join WHERE clauses &#8211; how should I write those? Example: SELECT p.FirstName + &#039; works in &#039; + d.DepartmentName AS &#039;Who Works Where&#039; [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/\" \/>\n<meta property=\"og:site_name\" content=\"Conor Cunningham\" \/>\n<meta property=\"article:published_time\" content=\"2008-03-31T19:47:00+00:00\" \/>\n<meta name=\"author\" content=\"Conor Cunningham\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Conor Cunningham\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/\",\"name\":\"How to write non-JOIN WHERE clauses - Conor Cunningham\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#website\"},\"datePublished\":\"2008-03-31T19:47:00+00:00\",\"dateModified\":\"2008-03-31T19:47:00+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to write non-JOIN WHERE clauses\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/\",\"name\":\"Conor Cunningham\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3\",\"name\":\"Conor Cunningham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g\",\"caption\":\"Conor Cunningham\"},\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/author\/conor\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to write non-JOIN WHERE clauses - Conor Cunningham","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/","og_locale":"en_US","og_type":"article","og_title":"How to write non-JOIN WHERE clauses - Conor Cunningham","og_description":"Based on my previous post describing the differences between ANSI-89 and ANSI-92+ join syntaxes and recommendations, I had a follow-up question in a comment which was (paraphrased) What do I do with non-join WHERE clauses &#8211; how should I write those? Example: SELECT p.FirstName + ' works in ' + d.DepartmentName AS 'Who Works Where' [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/","og_site_name":"Conor Cunningham","article_published_time":"2008-03-31T19:47:00+00:00","author":"Conor Cunningham","twitter_misc":{"Written by":"Conor Cunningham","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/","url":"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/","name":"How to write non-JOIN WHERE clauses - Conor Cunningham","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#website"},"datePublished":"2008-03-31T19:47:00+00:00","dateModified":"2008-03-31T19:47:00+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/how-to-write-non-join-where-clauses\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/conor\/"},{"@type":"ListItem","position":2,"name":"How to write non-JOIN WHERE clauses"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/conor\/","name":"Conor Cunningham","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/conor\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3","name":"Conor Cunningham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g","caption":"Conor Cunningham"},"url":"https:\/\/www.sqlskills.com\/blogs\/conor\/author\/conor\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts\/399","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/comments?post=399"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts\/399\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/media?parent=399"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/categories?post=399"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/tags?post=399"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}