Pourquoi les caractères génériques dans les instructions GROUP BY ne fonctionnent-ils pas?

29

J'essaie de faire fonctionner l'instruction SQL suivante, mais j'obtiens une erreur de syntaxe:

SELECT A.*, COUNT(B.foo)
FROM TABLE1 A
LEFT JOIN TABLE2 B ON A.PKey = B.FKey
GROUP BY A.*

Ici, A est un tableau large avec 40 colonnes et je voudrais éviter si possible de lister chaque nom de colonne dans la clause GROUP BY. J'ai beaucoup de ces tables sur lesquelles je dois exécuter une requête similaire, donc je vais devoir écrire une procédure stockée. Quelle est la meilleure façon d'aborder cela?

J'utilise MS SQL Server 2008.

Maximus anonyme
la source

Réponses:

32

GROUP BY A.* n'est pas autorisé dans SQL.

Vous pouvez contourner cela en utilisant une sous-requête dans laquelle vous vous regroupez, puis rejoignez:

SELECT A.*, COALESCE(B.cnt, 0) AS Count_B_Foo
FROM TABLE1 AS A
  LEFT JOIN 
      ( SELECT FKey, COUNT(foo) AS cnt
        FROM TABLE2 
        GROUP BY FKey
      ) AS B 
    ON A.PKey = B.FKey ;

Il existe une fonctionnalité dans la norme SQL-2003 pour autoriser dans la SELECTliste, les colonnes qui ne sont pas dans la GROUP BYliste, tant qu'elles en dépendent fonctionnellement. Si cette fonctionnalité avait été implémentée dans SQL-Server, votre requête aurait pu être écrite comme suit:

SELECT A.*, COUNT(B.foo)
FROM TABLE1 A
LEFT JOIN TABLE2 B ON A.PKey = B.FKey
GROUP BY A.pk                          --- the Primary Key of table A

Malheureusement, cette fonctionnalité n'a pas encore été implémentée, pas même dans la version SQL-Server 2012 - et pas dans aucun autre SGBD pour autant que je sache. À l'exception de MySQL qui l'a mais de manière inadéquate (insuffisamment comme: la requête ci-dessus fonctionnera mais le moteur ne vérifiera pas la dépendance fonctionnelle et d'autres requêtes mal écrites afficheront des résultats faux et semi-aléatoires).

Comme @Mark Byers nous l'a informé dans un commentaire, PostgreSQL 9.1 a ajouté une nouvelle fonctionnalité conçue à cet effet. Elle est plus restrictive que l'implémentation de MySQL.

ypercubeᵀᴹ
la source
Pouvez-vous mentionner quelques SGBDR qui mettent en œuvre cette partie de la norme telle qu'écrite? Je sais, par exemple, que MySQL vous permettra (compte tenu des paramètres appropriés) d'inclure des éléments qui ne figurent pas dans la GROUP BYclause de la SELECTliste, mais cela ne permet pas de définir de quelle ligne cette valeur proviendra (donc si la colonne ou l'expression n'est pas « t fonctionnellement dépendant de l'expression de regroupement, il peut provenir d'une rangée au sein du groupe).
Adam Robinson
@Adam: Non, je ne connais aucun SGBDR qui l'ait implémenté. MySQL l'a mais de manière insuffisante, comme le dit votre commentaire.
ypercubeᵀᴹ
Je t'ai eu. Je demandais en fait s'il y en avait, car j'ai l'expérience avec beaucoup moins de SGBDR que j'imagine que la plupart des personnes répondant aux questions sur ce site auraient;) Mais c'était mon soupçon.
Adam Robinson
3
"et pas dans tout autre SGBD pour autant que je sache." PostgreSQL 9.1 a ajouté une nouvelle fonctionnalité conçue à cet effet. Elle est plus restrictive que l'implémentation de MySQL.
Mark Byers
@MarkByers: thnx, je ne le savais pas.
ypercubeᵀᴹ
24

En plus de la solution de contournement de @ ypercube, "taper" n'est jamais une excuse pour l'utiliser SELECT *. J'ai écrit à ce sujet ici , et même avec la solution de contournement, je pense que votre SELECTliste devrait toujours inclure les noms des colonnes - même s'il y en a un grand nombre comme 40.

Pour faire court, vous pouvez éviter de taper ces grandes listes en cliquant et en faisant glisser le nœud Colonnes de l'objet dans l'Explorateur d'objets vers votre fenêtre de requête. La capture d'écran montre une vue mais la même chose peut être faite pour une table.

entrez la description de l'image ici

Mais si vous voulez lire toutes les raisons pour lesquelles vous devriez vous soumettre à cet énorme niveau d'effort de faire glisser un élément de quelques centimètres, veuillez lire mon article . :-)

Aaron Bertrand
la source
Dans PostgreSQL (avec EMS SQL Manager), je fais cela en définissant une vue en tant que SELECT *, puis en copiant la liste des champs à partir de la définition de la vue.
dezso
Je suis certainement d'accord que cela SELECT *ne devrait pas être utilisé. Je suis curieux de savoir GROUP BYsi l' affaire. @Aaron, y a-t-il des problèmes d'efficacité avec 40 colonnes dans la liste Group By?
ypercubeᵀᴹ
1
@ypercube - Pour autant que je l'ai vu, si vous le regroupez, A.PK, A.some, A.other, A.columnscela ne dérange pas de le comparer, some, other, columnsc'est juste requis par la syntaxe.
Martin Smith
1
@datagod désolé, non, les lacunes ne pouvaient être expliquées que par l'équipe de développement SSMS. :-)
Aaron Bertrand
1
@Pacerier Désolé, je ne suis pas du tout d'accord , mais vous pourriez peut-être élaborer.
Aaron Bertrand