How to execute UNION without sorting? (SQL)

前端 未结 10 588
猫巷女王i
猫巷女王i 2021-01-30 21:34

UNION joins two results and remove duplicates, while UNION ALL does not remove duplicates.
UNION also sort the final output.

W

相关标签:
10条回答
  • 2021-01-30 22:03

    You can do something like this.

    Select distinct name from  (SELECT r.name FROM outsider_role_mapping orm1 
        union all
    SELECT r.name FROM user_role_mapping orm2
    ) tmp;
    
    0 讨论(0)
  • 2021-01-30 22:06

    Consider these tables (Standard SQL code, runs on SQL Server 2008):

    WITH A 
         AS 
         (
          SELECT * 
            FROM (
                  VALUES (1), 
                         (2), 
                         (3), 
                         (4), 
                         (5), 
                         (6) 
                 ) AS T (col)
         ),
         B 
         AS 
         (
          SELECT * 
            FROM (
                  VALUES (9), 
                         (8), 
                         (7), 
                         (6), 
                         (5), 
                         (4) 
                 ) AS T (col)
         ), ...
    

    The desired effect is this to sort table A by col ascending, sort table B by col descending then unioning the two, removing duplicates, retaining order before the union and leaving table A results on the "top" with table B on the "bottom" e.g. (pesudo code)

    (
     SELECT *
       FROM A
      ORDER 
         BY col
    )
    UNION
    (
     SELECT *
       FROM B
      ORDER 
         BY col DESC
    );
    

    Of course, this won't work in SQL because there can only be one ORDER BY clause and it can only be applied to the top level table expression (or whatever the output of a SELECT query is known as; I call it the "resultset").

    The first thing to address is the intersection between the two tables, in this case the values 4, 5 and 6. How the intersection should be sorted needs to be specified in SQL code, therefore it is desirable that the designer specifies this too! (i.e. the person asking the question, in this case).

    The implication in this case would seem to be that the intersection ("duplicates") should be sorted within the results for table A. Therefore, the sorted resultset should look like this:

          VALUES (1), -- A including intersection, ascending
                 (2), -- A including intersection, ascending
                 (3), -- A including intersection, ascending
                 (4), -- A including intersection, ascending
                 (5), -- A including intersection, ascending
                 (6), -- A including intersection, ascending
                 (9), -- B only, descending 
                 (8), -- B only, descending  
                 (7), -- B only, descending 
    

    Note in SQL "top" and "bottom" has no inferent meaning and a table (other than a resultset) has no inherent ordering. Also (to cut a long story short) consider that UNION removes duplicate rows by implication and must be applied before ORDER BY. The conclusion has to be that each table's sort order must be explicitly defined by exposing a sort order column(s) before being unioned. For this we can use the ROW_NUMBER() windowed function e.g.

         ...
         A_ranked
         AS
         (
          SELECT col, 
                 ROW_NUMBER() OVER (ORDER BY col) AS sort_order_1
            FROM A                      -- include the intersection
         ),
         B_ranked
         AS
         (
          SELECT *, 
                 ROW_NUMBER() OVER (ORDER BY col DESC) AS sort_order_1
            FROM B
           WHERE NOT EXISTS (           -- exclude the intersection
                             SELECT * 
                               FROM A
                              WHERE A.col = B.col 
                            )
         )
    SELECT *, 1 AS sort_order_0 
      FROM A_ranked
    UNION
    SELECT *, 2 AS sort_order_0 
      FROM B_ranked
    ORDER BY sort_order_0, sort_order_1;
    
    0 讨论(0)
  • 2021-01-30 22:10
    select T.Col1, T.Col2, T.Sort
    from 
        (
          select T.Col1,
                 T.Col2,
                 T.Sort,
                 rank() over(partition by T.Col1, T.Col2 order by T.Sort) as rn
          from
              (
                select Col1, Col2, 1 as Sort
                from Table1
                union all
                select Col1, Col2, 2
                from Table2
              ) as T
        ) as T
    where T.rn = 1    
    order by T.Sort
    
    0 讨论(0)
  • 2021-01-30 22:13

    The sort is used to eliminate the duplicates, and is implicit for DISTINCT and UNION queries (but not UNION ALL) - you could still specify the columns you'd prefer to order by if you need them sorted by specific columns.

    For example, if you wanted to sort by the result sets, you could introduce an additional column, and sort by that first:

    SELECT foo, bar, 1 as ResultSet
    FROM Foo
    WHERE bar = 1
    UNION
    SELECT foo, bar, 2 as ResultSet
    FROM Foo
    WHERE bar = 3
    UNION
    SELECT foo, bar, 3 as ResultSet
    FROM Foo
    WHERE bar = 2
    ORDER BY ResultSet
    
    0 讨论(0)
提交回复
热议问题