PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Rails élargissant les champs avec portée, PG n'aime pas ça

Comme Frank l'a expliqué, PostgreSQL rejettera toute requête qui ne renvoie pas un ensemble reproductible de lignes.

Supposons que vous ayez une requête du type :

select a, b, agg(c)
from tbl
group by a

PostgreSQL le rejettera car b n'est pas spécifié dans le group by déclaration. Exécutez cela dans MySQL, en revanche, et il sera accepté. Dans ce dernier cas, cependant, lancez quelques insertions, mises à jour et suppressions, et l'ordre des lignes sur les pages du disque sera différent.

Si ma mémoire est bonne, les détails d'implémentation sont tels que MySQL triera réellement par a, b et renverra le premier b de l'ensemble. Mais en ce qui concerne la norme SQL, le comportement n'est pas spécifié - et bien sûr, PostgreSQL ne le fait pas toujours trier avant d'exécuter des fonctions d'agrégation.

Potentiellement, cela pourrait entraîner des valeurs différentes de b dans le jeu de résultats dans PostgreSQL. Et donc, PostgreSQL génère une erreur à moins que vous ne soyez plus précis :

select a, b, agg(c)
from tbl
group by a, b

Ce que Frank a souligné, c'est que, dans PostgreSQL 9.1, si a est la clé primaire, que vous pouvez laisser b non spécifié -- le planificateur a appris à ignorer les champs groupés suivants lorsque les clés primaires applicables impliquent une ligne unique.

Pour votre problème en particulier, vous devez spécifier votre groupe par comme vous le faites actuellement, plus chaque champ sur lequel vous basez votre agrégat, c'est-à-dire "widgets"."id", "widgets"."user_id", [snip] mais pas des trucs comme sum(amount) , qui sont les appels de fonction d'agrégation.

En tant que note secondaire hors sujet, je ne sais pas comment fonctionne votre ORM/modèle, mais le SQL qu'il génère n'est pas optimal. Beaucoup de ces jointures externes gauches semblent devoir être des jointures internes. Cela permettra au planificateur de choisir un ordre de participation approprié, le cas échéant.