web-dev-qa-db-fra.com

GROUP BY sans fonction d'agrégat

J'essaie de comprendre GROUP BY (nouveauté d'Oracle dbms) sans fonction d'agrégat.
Comment ça marche?
Voici ce que j'ai essayé. 

Table EMP sur laquelle je vais lancer mon SQL.
EMP TABLE

SELECT ename , sal
FROM emp
GROUP BY ename , sal

Result

SELECT ename , sal  
FROM emp  
GROUP BY ename;  

Résultat

ORA-00979: pas une expression GROUP BY
00979. 00000 - "pas une expression GROUP BY"
*Cause:
*Action:
Erreur à la ligne: 397 Colonne: 16 

SELECT ename , sal  
FROM emp  
GROUP BY sal;  

Résultat

ORA-00979: pas une expression GROUP BY
00979. 00000 - "pas une expression GROUP BY"
*Cause:
* Action: Erreur à la ligne: 411 Colonne: 8 

SELECT empno , ename , sal  
FROM emp  
GROUP BY sal , ename;  

Résultat

ORA-00979: pas une expression GROUP BY
00979. 00000 - "pas une expression GROUP BY"
*Cause:
* Action: Erreur à la ligne: 425 Colonne: 8 

SELECT empno , ename , sal  
FROM emp  
GROUP BY empno , ename , sal;  

Result

Donc, fondamentalement, le nombre de colonnes doit être égal au nombre de colonnes de la clause GROUP BY, mais je ne comprends toujours pas pourquoi ni ce qui se passe.

46
XForCE07

C'est comme ça que GROUP BY fonctionne. Il faut plusieurs lignes et les transforme en une seule ligne. Pour cette raison, il doit savoir quoi faire avec toutes les lignes combinées dans lesquelles il existe des valeurs différentes pour certaines colonnes (champs). C'est pourquoi vous avez deux options pour chaque champ que vous voulez sélectionner: soit l'inclure dans la clause GROUP BY, soit l'utiliser dans une fonction d'agrégat afin que le système sache comment vous souhaitez combiner le champ.

Par exemple, supposons que vous ayez ce tableau:

Name | OrderNumber
------------------
John | 1
John | 2

Si vous dites GROUP BY Name, comment saura-t-il quel numéro de commande afficher dans le résultat? Vous devez donc soit inclure OrderNumber dans group by, ce qui donnera ces deux lignes. Ou bien, vous utilisez une fonction d'agrégat pour montrer comment gérer les numéros d'ordre. Par exemple, MAX(OrderNumber), ce qui signifie que le résultat est John | 2 ou SUM(OrderNumber), ce qui signifie que le résultat est John | 3.

83
Tobberoth

Compte tenu de ces données:

Col1  Col2  Col3
 A     X     1
 A     Y     2
 A     Y     3
 B     X     0
 B     Y     3
 B     Z     1

Cette requête 

SELECT Col1, Col2, Col3 FROM data GROUP BY Col1, Col2, Col3

Cela donnerait exactement la même table.

Cependant, cette requête:

SELECT Col1, Col2 FROM data GROUP BY Col1, Col2

Aboutirait à 

Col1  Col2
 A     X  
 A     Y  
 B     X  
 B     Y  
 B     Z  

Maintenant, une requête:

SELECT Col1, Col2, Col3 FROM data GROUP BY Col1, Col2

Cela créerait un problème: la ligne avec A, Y est le résultat du regroupement des deux lignes 

 A     Y     2
 A     Y     3

Alors, quelle valeur devrait être dans Col3, '2' ou '3'?

Normalement, vous utiliseriez un groupe pour calculer, par exemple, une somme:

SELECT Col1, Col2, SUM(Col3) FROM data GROUP BY Col1, Col2

Donc dans la ligne nous avons eu un problème avec nous obtenons maintenant (2 + 3) = 5.

Le regroupement de toutes vos colonnes dans votre sélection est en fait identique à l'utilisation de DISTINCT. Dans ce cas, il est préférable d'utiliser le mot-clé DISTINCT.

Donc au lieu de 

SELECT Col1, Col2, Col3 FROM data GROUP BY Col1, Col2, Col3

utilisation

SELECT DINSTINCT Col1, Col2, Col3 FROM data
20
oerkelens

Vous rencontrez une exigence strict de la clause GROUP BY. Chaque colonne ne figurant pas dans la clause group-by doit avoir une fonction appliquée pour réduire tous les enregistrements du "groupe" correspondant à un seul enregistrement (somme, max, min, etc.).

Si vous répertoriez toutes les colonnes (sélectionnées) interrogées dans la clause GROUP BY, vous demandez essentiellement que les enregistrements en double soient exclus du jeu de résultats. Cela donne le même effet que SELECT DISTINCT, qui élimine également les lignes en double du jeu de résultats.

20
Mister_Tom

Le seul cas d'utilisation réel de GROUP BY sans agrégation est lorsque GROUP BY est supérieur au nombre de colonnes sélectionnées, auquel cas les colonnes sélectionnées peuvent être répétées. Sinon, vous pouvez aussi bien utiliser un DISTINCT.

Il est à noter que les autres SGBDR n'exigent pas que toutes les colonnes non agrégées soient incluses dans GROUP BY. Par exemple, dans PostgreSQL, si les colonnes de clé primaire d'une table sont incluses dans GROUP BY, il n'est pas nécessaire que les autres colonnes de cette table le soient, car elles sont garanties distinctes pour chaque colonne de clé primaire distincte. Par le passé, j'ai souhaité qu'Oracle fasse de même pour un SQL plus compact dans de nombreux cas.

6
David Aldridge

Me laisser donner quelques exemples.

Considérez ces données.

CREATE TABLE DATASET ( VAL1 CHAR ( 1 CHAR ),
                   VAL2 VARCHAR2 ( 10 CHAR ),
                   VAL3 NUMBER );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'b', 'b-details', 2 );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'a', 'a-details', 1 );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'c', 'c-details', 3 );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'a', 'dup', 4 );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'c', 'c-details', 5 );

COMMIT;

Quoi de neuf dans la table maintenant

SELECT * FROM DATASET;

VAL1 VAL2             VAL3
---- ---------- ----------
b    b-details           2
a    a-details           1
c    c-details           3
a    dup                 4
c    c-details           5

5 rows selected.

--agréger avec group par

SELECT
      VAL1,
      COUNT ( * )
FROM
      DATASET A
GROUP BY
      VAL1;

VAL1   COUNT(*)
---- ----------
b             1
a             2
c             2

3 rows selected.

--aggregate with group by multiple column mais sélectionne une colonne partielle

SELECT
      VAL1,
      COUNT ( * )
FROM
      DATASET A
GROUP BY
      VAL1,
      VAL2;

VAL1  
---- 
b             
c             
a             
a             

4 rows selected.

--Aucun agrégat avec groupe par plusieurs colonnes

SELECT
      VAL1,
      VAL2
FROM
      DATASET A
GROUP BY
      VAL1,
      VAL2;

    VAL1  
    ---- 
    b    b-details
    c    c-details
    a    dup
    a    a-details

    4 rows selected.

--Aucun agrégat avec groupe par plusieurs colonnes

SELECT
      VAL1
FROM
      DATASET A
GROUP BY
      VAL1,
      VAL2;

    VAL1  
    ---- 
    b
    c
    a
    a

    4 rows selected.

Vous avez N colonnes dans select (à l'exclusion des agrégations), vous devriez alors avoir N ou N + x colonnes

4
SriniV

Si vous avez une colonne dans la clause SELECT, comment va-t-elle la sélectionner s'il y a plusieurs lignes? alors oui, chaque colonne de la clause SELECT doit être dans la clause GROUP BY également, vous pouvez utiliser des fonctions d'agrégat dans SELECT ... 

vous pouvez avoir une colonne dans la clause GROUP BY qui n'est pas dans la clause SELECT, mais pas autrement

3
ogres

Utilisez la sous-requête, par exemple: 

SELECT field1,field2,(SELECT distinct field3 FROM tbl2 WHERE criteria) AS field3
FROM tbl1 GROUP BY field1,field2

OR

SELECT DISTINCT field1,field2,(SELECT distinct field3 FROM tbl2 WHERE criteria) AS field3
FROM tbl1
2

En plus

fondamentalement, le nombre de colonnes doit être égal au nombre de colonnes de la clause GROUP BY

n'est pas une déclaration correcte.

  • Tout attribut ne faisant pas partie de la clause GROUP BY ne peut pas être utilisé pour la sélection.
  • Tout attribut faisant partie de la clause GROUP BY peut être utilisé pour la sélection mais n'est pas obligatoire. 
1
sancz

Je sais que vous avez dit vouloir comprendre groupe par si vous avez des données comme celle-ci:

COL-A  COL-B  COL-C  COL-D
  1      Ac      C1     D1
  2      Bd      C2     D2
  3      Ba      C1     D3
  4      Ab      C1     D4
  5      C       C2     D5

Et vous voulez que les données apparaissent comme:

COL-A  COL-B  COL-C  COL-D
  4      Ab      C1     D4
  1      Ac      C1     D1
  3      Ba      C1     D3
  2      Bd      C2     D2
  5      C       C2     D5

Tu utilises:

select * from table_name
order by col-c,colb

Parce que je pense que c'est ce que vous avez l'intention de faire.

0
user2839702