{"id":736,"date":"2018-11-03T14:34:04","date_gmt":"2018-11-03T18:34:04","guid":{"rendered":"http:\/\/pmcgovern.ca\/wp\/?p=736"},"modified":"2020-05-10T13:53:54","modified_gmt":"2020-05-10T17:53:54","slug":"fun-with-common-table-expressions","status":"publish","type":"post","link":"https:\/\/pmcgovern.ca\/wp\/?p=736","title":{"rendered":"Fun With Common Table Expressions"},"content":{"rendered":"<p>I came across some interesting ways to use common table expressions (CTE) in SQL Server and pass them on in the hope someone may find them useful. The first example shows how to use a CTE to update a table, and the second illustrates a technique for comparing a row with a previous row.<\/p>\n<p><strong>Update a CTE<\/strong><\/p>\n<p>Suppose you inherit a table that keeps track of tools. For this example, assume tools reside in toolboxes, only in boxes, and only one box at a time. Furthermore, the toolboxes cannot be nested like <em>matryoshka<\/em>. The rows are in no particular order:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ini\">Toolbox | Tool \n----------------- \nRed     | Pliers \nRed     | Hammer \nRed     | Robertson screwdriver \nBlue    | Wire cutters \nBlue    | Utility knife \nBlue    | Phillips screwdriver<\/pre>\n<p>Now suppose your requirements change and you must assign a number to each tool, by toolbox. You could use a cursor to iterate over the rows and maintain a counter, but I&#8217;ve always found them clumsy.<\/p>\n<p>Add a new integer column, <strong>RECORD_NUM<\/strong> and run a CTE to generate a count for each row by toolbox, and then update the CTE with the count:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">;WITH CTE_RN AS (\n  SELECT ROW_NUMBER() OVER (\n    PARTITION BY TOOLBOX ORDER BY (SELECT 1)) AS RN,\n    RECORD_NUM FROM TOOLBOX ) \nUPDATE CTE_RN SET CTE_RN.RECORD_NUM=CTE_RN.RN<\/pre>\n<p>Nice and neat. <strong>RECORD_NUM<\/strong> must be selected by the CTE in order to make it available to the update statement. The <strong>SELECT 1<\/strong> in the <strong>ORDER BY<\/strong> clause does not provide order of any kind, which is fine because the rows are in no particular order. When run, is updates the table to the following:<\/p>\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ini\">Toolbox | Tool                  | RECORD_NUM\n--------------------------------------------\nRed     | Pliers                | 1\nRed     | Hammer                | 2\nRed     | Robertson screwdriver | 3 \nBlue    | Wire cutters          | 1\nBlue    | Utility knife         | 2\nBlue    | Phillips screwdriver  | 3\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Compare with Previous Row<\/strong><\/p>\n<p>Computing the difference of a value between one date and the next is a common task, but you have to jump through a few hoops to get an answer with SQL.<\/p>\n<p>Here we have <strong>FOO.FOOBAR<\/strong> and we want to know the change of <strong>VALUE<\/strong> from month to month.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ini\">DATE       | VALUE\n------------------\n2018-01-01 | 10\n2018-02-01 | 20\n2018-03-01 | 30\n2018-04-01 | 40\n2018-05-01 | 50\n<\/pre>\n<p>CTEs and ranking functions provide a clean implementation.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">;WITH CTE_DATES AS (\n  SELECT [DATE], VALUE,\n  DENSE_RANK OVER (ORDER BY [DATE] DESC) AS RK\n  FROM FOO.FOOBAR )\nSELECT\n  CUR.DATE AS CURRENT,\n  PREV.DATE AS PREVIOUS,\n  CUR.VALUE - PREV.VALUE AS DIFF FROM CTE_DATES CUR\n  INNER JOIN CTE_DATES PREV ON PREV.RK=(CUR.RK + 1)\n  ORDER BY CUR.DATE DESC\n<\/pre>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/t-sql\/functions\/dense-rank-transact-sql?view=sql-server-2017\">DENSE_RANK()<\/a> produces a continuous series, with no gaps. This continuity guarantees that the inner join on line 10 matches with the previous row. It generates the following results:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ini\">CURRENT    | PREVIOUS   | DIFF\n------------------------------\n2018-05-01 | 2018-04-01 | 10 \n2018-04-01 | 2018-03-01 | 10 \n2018-03-01 | 2018-02-01 | 10 \n2018-02-01 | 2018-01-01 | 10 \n<\/pre>\n<p>There a a number of other ways to do this kind kind of row-by-row comparison, but this method is the cleanest I have come across.<\/p>\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I came across some interesting ways to use common table expressions (CTE) in SQL Server and pass them on in the hope someone may find them useful. The first example shows how to use a CTE to update a table,&#8230;<\/p>\n","protected":false},"author":1,"featured_media":740,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[13],"class_list":["post-736","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming","tag-programming"],"_links":{"self":[{"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=\/wp\/v2\/posts\/736","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=736"}],"version-history":[{"count":34,"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=\/wp\/v2\/posts\/736\/revisions"}],"predecessor-version":[{"id":859,"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=\/wp\/v2\/posts\/736\/revisions\/859"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=\/wp\/v2\/media\/740"}],"wp:attachment":[{"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=736"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=736"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pmcgovern.ca\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=736"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}