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.
SELECT ename , sal
FROM emp
GROUP BY ename , sal
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;
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.
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
.
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
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.
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.
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
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
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
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.
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.