Quantcast
Channel: Active questions tagged cte - Database Administrators Stack Exchange
Viewing all articles
Browse latest Browse all 213

CTE with UNION ALL not working as expected

$
0
0

The query below seems simple and straightforward, yet it produces unexpected results.


CREATE TABLE #NUMBERS(    N BIGINT);INSERT INTO #NUMBERS VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9);WITHA AS(       -- CHOOSE A ROW AT RANDOM    SELECT   TOP 1 *    FROM     #NUMBERS                ORDER BY NewID()           ),B AS(    SELECT A.N AS QUANTITY, 'METERS' AS UNIT FROM A    UNION ALL    SELECT A.N*100 AS QUANTITY, 'CENTIMETERS' AS UNIT FROM A    UNION ALL    SELECT A.N*1000 AS QUANTITY, 'MILLIMETERS' AS UNIT FROM A    UNION ALL    SELECT A.N*1000000 AS QUANTITY, 'MICRONS' AS UNIT FROM A    UNION ALL    SELECT A.N*1000000000 AS QUANTITY, 'NANOMETERS' AS UNIT FROM A)SELECT   *FROM     BORDER BY B.QUANTITY;

I would expect it to execute CTE A once, and then carry those results into CTE B to produce results something like this:

QUANTITYUNIT
4METERS
400CENTIMETERS
4000MILLIMETERS
4000000MICRONS
4000000000NANOMETERS

However, it produces results like this:

QUANTITYUNIT
8METERS
700CENTIMETERS
1000MILLIMETERS
6000000MICRONS
3000000000NANOMETERS

It means it is going back and executing CTE A five times, once for every mention of A in CTE B. Not only is this unwanted and unintuitive, but it also seems unnecessarily inefficient.

What is going on, and how would a CTE genius rewrite it to produce the desired results?


BTW, the Microsoft documentation pages on CTEs contain this cryptic statement which might or might not be related:

If more than one CTE_query_definition is defined, the query definitions must be joined by one of these set operators: UNION ALL, UNION, EXCEPT, or INTERSECT.


Finally, rewriting the query to eliminate CTE B didn't help:

WITHA AS(       -- CHOOSE A ROW AT RANDOM    SELECT   TOP 1 *    FROM     #NUMBERS                ORDER BY NewID()           )SELECT   *FROM     (          SELECT A.N AS QUANTITY, 'METERS' AS UNIT FROM A          UNION ALL          SELECT A.N*100 AS QUANTITY, 'CENTIMETERS' AS UNIT FROM A          UNION ALL          SELECT A.N*1000 AS QUANTITY, 'MILLIMETERS' AS UNIT FROM A          UNION ALL          SELECT A.N*1000000 AS QUANTITY, 'MICRONS' AS UNIT FROM A          UNION ALL          SELECT A.N*1000000000 AS QUANTITY, 'NANOMETERS' AS UNIT FROM A         ) AS BORDER BY B.QUANTITY;

Viewing all articles
Browse latest Browse all 213

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>