web-dev-qa-db-fra.com

SELECT DISTINCT avec LEFT JOIN, ORDERed BY dans t-SQL

J'ai le tableau suivant dans SQL Server 2008:

CREATE TABLE tbl (ID INT, dtIn DATETIME2, dtOut DATETIME2, Type INT)

INSERT tbl VALUES
(1, '05:00', '6:00', 1),
(2, '05:00', '7:00', 1),
(3, '05:01', '8:00', 1),
(4, '05:00', '8:00', 1),
(5, '05:00', '6:00', 2),
(6, '05:00', '7:00', 2)

qui sélectionne les ID de tous les enregistrements du même type, avec la même date dtIn, classés par stOut dans l'ordre croissant:

SELECT DISTINCT tbl.id FROM tbl   
  LEFT JOIN tbl AS t1
  ON tbl.type = t1.type AND
     tbl.dtIn = t1.dtIn
  ORDER BY tbl.dtOut ASC

Mais cela me donne une erreur:

Les éléments ORDER BY doivent apparaître dans la liste de sélection si SELECT DISTINCT est spécifié

J'ai essayé de mettre cet ORDER BY à différents endroits et tout ne semble pas fonctionner. Qu'est-ce que je fais de mal ici?

9
ahmd0

Lorsque vous réduisez les identifiants individuels, vous créez la possibilité que chaque identifiant puisse avoir plus d'un dtOut associé. Lorsque cela se produit, comment Sql Server saura-t-il quel ordre utiliser?

Tu pourrais essayer:

SELECT t1.id
FROM tbl t1
LEFT JOIN  tbl t2 on t1.type = t2.type AND t1.dtIn = t2.dtIn
GROUP BY t1.id, t2.dtOut
ORDER BY t2.dtOut

Cependant, comme je l'ai mentionné ci-dessus, cela peut ouvrir la possibilité d'avoir le même identifiant répertorié plus d'une fois, s'il correspond à plus d'un enregistrement sur la table de droite.

5
Joel Coehoorn

Cela n'a pas de sens de COMMANDER par une colonne qui n'est pas incluse dans la liste des éléments DISTINCT.

Utilisons un scénario simple. Tout d'abord, une table FruitPerson:

Fruit  PersonName
-----  ------
Apple  Joe
Apple  Mary
Peach  Karen
Peach  Lance

Voici la requête équivalente à ce que vous essayez de faire:

SELECT DISTINCT Fruit
FROM FruitPerson
ORDER BY PersonName;

Le résultat de cette requête sans le ORDER BY est-ce:

Fruit
-----
Apple
Peach

Mais maintenant, la question est: comment le moteur doit-il ordonner ces deux valeurs "Apple" et "Peach" par PersonName? Lequel PersonNames? Il y a deux personnes par fruit! Quel (s) nom (s), exactement, doit-il utiliser pour décider si Apple ou Peach vient en premier?

Au lieu de cela, réécrivez votre requête sous forme d'agrégat:

SELECT Fruit, MinName = Min(PersonName) -- which name to order on
FROM FruitPerson
GROUP BY Fruit -- here's how you get your distinctness
ORDER BY MinName;
6
ErikE

Vous rencontriez cette erreur car vous n'avez pas mis (tbl.dtOut) dans la liste de sélection.

SELECT DISTINCT tbl.dtOut FROM tbl    
  LEFT JOIN tbl AS t1  
  ON tbl.type = t1.type AND  
     tbl.dtIn = t1.dtIn  
  ORDER BY tbl.dtOut ASC

Vous obtiendrez un ensemble de résultats (ayant 3 lignes) et si vous voulez aussi le champ id alors

SELECT DISTINCT tbl.dtOut, tbl.ID FROM tbl      
  LEFT JOIN tbl AS t1  
  ON tbl.type = t1.type AND  
     tbl.dtIn = t1.dtIn  
  ORDER BY tbl.dtOut ASC  

(ayant 6 lignes, car il donne la combinaison distincte hors champ id/date)

0
NG.

Vous ne pouvez utiliser que les colonnes de la clause ORDER BY qui font partie de votre instruction select lorsque vous utilisez la clé "DISTINCT" Word. Vous ne pouvez donc commander que par tbl.id

Si les identifiants sont uniques, le mot clé DISTINCT n'a aucun sens et entraînera une dégradation des performances et vous pouvez simplement le supprimer. Dans le cas où ils ne le sont pas et que vous décidez de sélectionner également tbl.dtOut tout en conservant DISTINCT, la paire tbl.id et tbl.dtOut peut vous donner plusieurs entrées ayant le même tbl.id, ce qui n'est probablement pas souhaité.

Vérifiez cet article pour les solutions de contournement possibles et l'explication des raisons pour lesquelles de telles requêtes sont interdites.

0
Andy

Vous devez inclure la colonne tbl.dtOut dans votre liste de sélection afin qu'elle sache sur quoi commander.

SELECT DISTINCT tbl.id, tbl.dtOut FROM tbl   
  LEFT JOIN tbl AS t1
  ON tbl.type = t1.type AND
     tbl.dtIn = t1.dtIn
  ORDER BY tbl.dtOut ASC
0
specman