Sql Union All * с * "отличным" - PullRequest
       34

Sql Union All * с * "отличным"

34 голосов
/ 26 сентября 2011

UNION объединяет два результата и удаляет дубликаты, а UNION ALL не удаляет дубликаты. UNION также сортирует окончательный результат.

Что я хочу, так это UNION ALL без дубликатов и без сортировки. Это возможно?

Причина этого в том, что я хочу, чтобы результат первого запроса был сверху окончательного результата, а второй запрос - снизу. (И каждый отсортирован так, как будто они работают отдельно)

Ответы [ 10 ]

47 голосов
/ 26 сентября 2011

Я заметил, что этот вопрос получил довольно много просмотров, поэтому сначала я отвечу на вопрос, который вы не задавали!

Относительно названия. Чтобы получить «Sql Union All с « отличным »», просто замените UNION ALL на UNION. Это приводит к удалению дубликатов.

Для вашего конкретного вопроса, учитывая пояснение «Первый запрос должен иметь« приоритет », поэтому дубликаты должны быть удалены снизу», вы можете использовать

SELECT col1,
       col2,
       MIN(grp) AS source_group
FROM   (SELECT 1 AS grp,
               col1,
               col2
        FROM   t1
        UNION ALL
        SELECT 2 AS grp,
               col1,
               col2
        FROM   t2) AS t
GROUP  BY col1,
          col2
ORDER  BY MIN(grp),
          col1  
10 голосов
/ 26 сентября 2011

«UNION также сортирует окончательный результат» - только как артефакт реализации. отнюдь не гарантированно выполнит сортировку, и если вам нужен конкретный порядок сортировки, вы должны указать его с предложением ORDER BY.В противном случае порядок вывода является наиболее удобным для сервера.

Таким образом, ваш запрос на функцию, которая выполняет UNION ALL, но удаляет дубликаты, прост - он называется UNION.


Из вашего пояснения вы также, похоже, полагаете, что UNION ALL вернет все результаты первого запроса до результатов последующих запросов.Это также не гарантируется.Опять же, единственный способ достичь определенного порядка - указать его с помощью предложения ORDER BY.

3 голосов
/ 26 сентября 2011

Рассмотрим эти таблицы (стандартный код SQL, работает на 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)
     ), ...

Желаемый эффект - сортировка таблицы A по col по возрастанию, сортировка таблицы B поcol по убыванию, затем объединение двух, удаление дубликатов, сохранение порядка перед объединением и выход из таблицы A результаты в «верху» с таблицей B в «низе», например (псевдокод)

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

Конечно, это не будет работать в SQL, потому что может быть только одно предложение ORDER BY, и его можно применять только к выражению таблицы верхнего уровня (или какому-либо другому результату запроса SELECT;Я называю это «набор результатов»).

Первое, на что нужно обратить внимание - это пересечение двух таблиц, в данном случае это значения 4, 5 и 6.Способ сортировки пересечения должен быть указан в коде SQL, поэтому желательно, чтобы конструктор также указывал это!(т.е. человек, задающий вопрос, в данном случае).

В этом случае может показаться, что пересечение («дубликаты») должно быть отсортировано в результатах для таблицы A. Следовательно, отсортированный набор результатов должен выглядеть следующим образом:

      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 

Примечание: в SQL "top" и "bottom" не имеют никакого промежуточного значения, а таблица (кроме результирующего набора) не имеет внутреннего порядка.Также (короче говоря) учтите, что UNION удаляет повторяющиеся строки косвенно и должно применяться до ORDER BY.Необходимо сделать вывод, что порядок сортировки каждой таблицы должен быть явно определен путем предоставления столбцов порядка сортировки перед объединением .Для этого мы можем использовать оконную функцию ROW_NUMBER(), например,

     ...
     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;
3 голосов
/ 26 сентября 2011
SELECT *, 1 AS sort_order
  FROM table1
 EXCEPT 
SELECT *, 1 AS sort_order
  FROM table2
UNION
SELECT *, 1 AS sort_order
  FROM table1
 INTERSECT 
SELECT *, 1 AS sort_order
  FROM table2
UNION
SELECT *, 2 AS sort_order
  FROM table2
 EXCEPT 
SELECT *, 2 AS sort_order
  FROM table1
ORDER BY sort_order;

Но реальный ответ таков: кроме условия ORDER BY, порядок сортировки будет произвольным и не гарантируется.

1 голос
/ 27 февраля 2019

Попробуйте это:

  SELECT DISTINCT * FROM (

      SELECT  column1, column2 FROM Table1
      UNION ALL
      SELECT  column1, column2 FROM Table2
      UNION ALL
      SELECT  column1, column2 FROM Table3

  ) X ORDER BY Column1
1 голос
/ 26 сентября 2011
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 голосов
/ 04 января 2019

Вы можете сделать что-то вроде этого.

Select distinct name from  (SELECT r.name FROM outsider_role_mapping orm1 
    union all
SELECT r.name FROM user_role_mapping orm2
) tmp;
0 голосов
/ 08 мая 2017

1,1: select 1 from dual union all select 1 from dual 1: select 1 from dual union select 1 from dual

0 голосов
/ 26 сентября 2011

Я предполагаю, что ваши таблицы - table1 и table2 соответственно, а ваше решение -

(select * from table1 MINUS select * from table2)
UNION ALL
(select * from table2 MINUS select * from table1)
0 голосов
/ 26 сентября 2011

Сортировка используется для устранения дубликатов и неявна для DISTINCT и UNION запросов (но не UNION ALL) - вы все равно можете указать столбцы, по которым вы бы предпочли упорядочить, если вам нужно их отсортировать по конкретным столбцам.

Например, если вы хотите отсортировать по результирующим наборам, вы можете ввести дополнительный столбец и отсортировать по первому:

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
...