web-dev-qa-db-fra.com

Sql Union All * avec * "distinct"

UNION joint deux résultats et supprime les doublons, tandis que UNION ALL ne supprime pas les doublons. UNION trie également la sortie finale.

Ce que je veux, c'est l'UNION ALL sans doublons et sans tri. Est-ce possible?

La raison en est que je veux que le résultat de la première requête soit au-dessus du résultat final et la deuxième requête en bas. (Et chacun trié comme s'il était exécuté individuellement)

34
hightow

Je remarque que cette question reçoit beaucoup de vues, je vais donc d'abord répondre à une question que vous n'avez pas posez!

Concernant le titre. Pour obtenir une "union SQL totale avec " distinct "", remplacez simplement UNION ALL avec UNION. Cela a pour effet de supprimer les doublons.

Pour votre question spécifique, étant donné la clarification "La première requête doit avoir la" priorité ", donc les doublons doivent être supprimés du bas" vous pouvez utiliser

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  
47
Martin Smith

"UNION trie également la sortie finale" - uniquement comme un artefact d'implémentation. C'est par aucun moyen garanti pour effectuer le tri, et si vous avez besoin d'un ordre de tri particulier, vous devez le spécifier avec un ORDER BY clause. Sinon, l'ordre de sortie est celui qui convient le mieux au serveur.

En tant que tel, votre demande pour une fonction qui exécute un UNION ALL mais qui supprime les doublons est facile - il s'appelle UNION.


D'après vos éclaircissements, vous semblez également croire qu'un UNION ALL renverra tous les résultats de la première requête avant les résultats des requêtes suivantes. C'est aussi non garanti. Encore une fois, la seule façon d'atteindre un ordre particulier est de le spécifier à l'aide d'un ORDER BY clause.

10
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;

Mais la vraie réponse est: autre que le ORDER BY clause, l'ordre de tri sera arbitraire et non garanti.

3
onedaywhen

Considérez ces tables (code SQL standard, s'exécute sur 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)
     ), ...

L'effet souhaité est le suivant: trier la table A par col ascendante, trier la table B par col décroissante puis l'union des deux, supprimer les doublons, conserver l'ordre avant l'union et la sortie de la table A résultats en "haut" avec la table B en "bas" par exemple (code pesudo)

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

Bien sûr, cela ne fonctionnera pas en SQL car il ne peut y avoir qu'une seule clause ORDER BY Et elle ne peut être appliquée qu'à l'expression de table de niveau supérieur (ou quelle que soit la sortie d'une requête SELECT est dit: je l'appelle le "jeu de résultats").

La première chose à traiter est l'intersection entre les deux tables, dans ce cas les valeurs 4, 5 Et 6. La manière dont l'intersection doit être triée doit être spécifiée dans le code SQL, il est donc souhaitable que le concepteur le spécifie également! (c'est-à-dire la personne qui pose la question, dans ce cas).

L'implication dans ce cas semble être que l'intersection ("doublons") doit être triée dans les résultats du tableau A. Par conséquent, le jeu de résultats trié devrait ressembler à ceci:

      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 

Remarque en SQL "top" et "bottom" n'a pas de signification inférente et une table (autre qu'un jeu de résultats) n'a pas de classement inhérent. Aussi (pour faire court), considérez que UNION supprime les lignes en double par implication et doit être appliqué avant ORDER BY. La conclusion doit être que l'ordre de tri de chaque table doit être explicitement défini en exposant une ou plusieurs colonnes d'ordre de tri avant en cours d'union. Pour cela, nous pouvons utiliser la fonction fenêtrée ROW_NUMBER() par ex.

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

Essaye ça:

  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
Divya Agrawal
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
1
Mikael Eriksson

Le tri est utilisé pour éliminer les doublons et est implicite pour les requêtes DISTINCT et UNION (mais pas UNION ALL) - vous pouvez toujours spécifier les colonnes que vous préférez classer si vous en avez besoin triées par colonnes spécifiques.

Par exemple, si vous souhaitez trier par les jeux de résultats, vous pouvez introduire une colonne supplémentaire et trier par celle-ci en premier:

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
Rowland Shaw

Je suppose que vos tables sont respectivement table1 et table2, et votre solution est;

(select * from table1 MINUS select * from table2)
UNION ALL
(select * from table2 MINUS select * from table1)
0
dursun