UNION ALL in CTE

22,553

Solution 1

You need to make sure that both result sets have the same columns:

WITH Results_CTE AS
(
    SELECT
        t2.SomeIntKey2 as Key,
        ROW_NUMBER() OVER (ORDER BY SomeIntKey2) AS RowNum  
    FROM
        Table2 t2
    LEFT JOIN CalculatedData d
        ON  d.Key = t1.SomeIntKey2
    WHERE Postcode LIKE 'CHX 1XX%' 
    UNION ALL 
    SELECT
        t1.SomeIntKey1 as Key,
        0 as RowNum
    FROM
        Table1 t1
    LEFT JOIN CalculatedData d
        ON  d.Key = t1.SomeIntKey1
    WHERE Postcode LIKE 'CHX 1XX%' 
 )
 SELECT * FROM Results_CTE a INNER JOIN CalclatedData d ON a.SomeIntKey2 = d.Key
 WHERE RowNum >= 0 AND RowNum <= 10 OPTION(RECOMPILE) 

Please note that the second part of the UNION ALL now always returns 0 for the RowNum. If you want to have the RowNum column for the result of the UNION ALL you need another sub query:

WITH Results_CTE AS
(
    SELECT
        s.Key,
        ROW_NUMBER() OVER (ORDER BY s.Key) AS RowNum
    FROM
    (
        SELECT
            t2.SomeIntKey2 as Key,
        FROM
            Table2 t2
            LEFT JOIN CalculatedData d
                ON  d.Key = t1.SomeIntKey2
        WHERE Postcode LIKE 'CHX 1XX%' 
        UNION ALL 
        SELECT
            t1.SomeIntKey1 as Key
        FROM
            Table1 t1
            LEFT JOIN CalculatedData d
                ON  d.Key = t1.SomeIntKey1
        WHERE Postcode LIKE 'CHX 1XX%' 
     )
 )
 SELECT * FROM Results_CTE a INNER JOIN CalclatedData d ON a.SomeIntKey2 = d.Key
 WHERE RowNum >= 0 AND RowNum <= 10 OPTION(RECOMPILE) 

Solution 2

Your second SELECT in the your UNION ALL doesn't return the same number of columns, hence the problem.

Try:

;WITH Results_CTE AS (
  SELECT IntKey, ROW_NUMBER() OVER (ORDER BY IntKey) AS RowNum  
  FROM
  (
     SELECT t2.SomeIntKey2 AS IntKey
     FROM Table2 t2
        LEFT JOIN CalculatedData d ON d.Key = t1.SomeIntKey2
     WHERE Postcode LIKE 'CHX 1XX%' 
     UNION ALL 
     SELECT t1.SomeIntKey1 AS IntKey
     FROM Table1 t1
        LEFT JOIN CalculatedData d ON d.Key = t1.SomeIntKey1
     WHERE Postcode LIKE 'CHX 1XX%' 
  ) t
 ) 
SELECT * FROM Results_CTE a INNER JOIN CalclatedData d ON a.IntKey = d.Key
Share:
22,553
Echilon
Author by

Echilon

Developer and sci-fi geek from England.

Updated on January 25, 2020

Comments

  • Echilon
    Echilon over 4 years

    I'm trying to get a UNION ALL working with a CTE which I'm using for paging. I need to get all records matching a set of criteria from two tables, then page the results. The first table's CTE looks like this:

    ;WITH Results_CTE AS (SELECT t1.SomeIntKey1, ROW_NUMBER() OVER (ORDER BY SomeIntKey1) AS RowNum  
     FROM Table1 t1
     LEFT JOIN CalculatedData d ON d.Key = t1.SomeIntKey1
     WHERE Postcode LIKE 'CHX 1XX%' 
     ) SELECT * FROM Results_CTE a INNER JOIN CalclatedData d ON a.SomeIntKey1 = d.Key WHERE RowNum >= 0 AND RowNum <= 10 OPTION(RECOMPILE) 
    

    The second table's paging SQL (which works fine) is:

    ;WITH Results_CTE AS (SELECT t2.SomeIntKey2, ROW_NUMBER() OVER (ORDER BY SomeIntKey2) AS RowNum  
     FROM Table2 t2
     LEFT JOIN CalculatedData d ON d.Key = t1.SomeIntKey2
     WHERE Postcode LIKE 'CHX 1XX%' 
     ) SELECT * FROM Results_CTE a INNER JOIN CalclatedData d ON a.SomeIntKey2 = d.Key WHERE RowNum >= 0 AND RowNum <= 10 OPTION(RECOMPILE) 
    

    For the combined paged data, I've tried something like:

    ;WITH Results_CTE AS (SELECT t2.SomeIntKey2, ROW_NUMBER() OVER (ORDER BY SomeIntKey2) AS RowNum  
     FROM Table2 t2
     LEFT JOIN CalculatedData d ON d.Key = t1.SomeIntKey2
     WHERE Postcode LIKE 'CHX 1XX%' 
    UNION ALL 
    SELECT t1.SomeIntKey1
     FROM Table1 t1
     LEFT JOIN CalculatedData d ON d.Key = t1.SomeIntKey1
     WHERE Postcode LIKE 'CHX 1XX%' 
     ) SELECT * FROM Results_CTE a INNER JOIN CalclatedData d ON a.SomeIntKey2 = d.Key WHERE RowNum >= 0 AND RowNum <= 10 OPTION(RECOMPILE) 
    

    However, this results in an error: All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.

    I know UNION ALLs can be confusing at the best of times, especially with joins, but I'm essentially getting a list of INT keys from two tables, then joining them to a third which contains the data I need (keys from both tables will be present in the joined column on the Data table.

  • Echilon
    Echilon over 12 years
    Thanks. The problem was not inlcuding the middle select. Seems nasty but does the job.