Flux rss

Oracle - Les requêtes hiérarchiques

 
Collection CommentCaMarche.net
Cet article se base sur des tests et recherches réalisés dans la version 8.1.5 d'Oracle.

Introduction

Tout au long de cet article, nous allons nous intéresser à une structure de données permettant de créer un Forum de discussion, matérialisé par la table suivante :

===
SQL> create table messages (
  2  id number,
  3  id_parent number,
  4  titre varchar2(50),
  5  auteur varchar2(30),
  6  dateheure date,
  7  texte long);

Table créée.
SQL> alter table messages add primary key (id);

Table modifiée.
SQL> alter table messages modify dateheure default sysdate;

Table modifiée.
===

La colonne id_parent contient NULL si le message est le premier message d'un fil de discussion, sinon elle contient l'id du message auquel le message répond. La colonne dateheure a pour valeur par défaut la date système du serveur de base de données. On pourra donc se permettre de l'ignorer lors de l'insertion des messages.

Nous n'allons pas nous attarder sur l'enregistrement des messages dans la table (ordre SQL "insert"). Nous n'allons nous intéresser qu'à la façon dont les données sont lues dans la table, donc aux ordres SQL "select" qu'il faudra exécuter pour obtenir les résultats escomptés.

Voici un exemple de contenu de la table messages :

insert into messages (id, id_parent, titre, auteur, texte)
values (1, NULL, 'Combien d''oeufs dans la pate à crêpes ?',
'John', 'Quelqu''un sait-il combien il faut d''oeufs ?');

insert into messages (id, id_parent, titre, auteur, texte)
values (2, NULL, 'Sondage : votre marque de lait préférée',
'John', 'Dites-moi quelle est votre marque de lait préférée ?');

insert into messages (id, id_parent, titre, auteur, texte)
values (3,1, 'Re : Combien d''oeufs dans la pate à crêpes ?',
'Martine', 'Je crois que c''est 2 par personne non ?');

insert into messages (id, id_parent, titre, auteur, texte)
values (4,3, 'C''est sûrement ça', 'John', 'Tu dois avoir raison, merci !');

insert into messages (id, id_parent, titre, auteur, texte)
values (5,2, 'Re : Sondage : votre marque de lait préférée',
'Fifi', 'Moi c''est Lait Blanc');

insert into messages (id, id_parent, titre, auteur, texte)
values (6,2, 'Re : Sondage : votre marque de lait préférée',
'Petrus', 'SuperMilk');

insert into messages (id, id_parent, titre, auteur, texte)
values (7,4, 'Re : C''est sûrement ça', 'Martine', 'De rien ;o)');

insert into messages (id, id_parent, titre, auteur, texte)
values (8,2, 'Re : Sondage : votre marque de lait préférée',
'Fifi', 'Au fait pourquoi ce sondage ?');

insert into messages (id, id_parent, titre, auteur, texte)
values (9,2, 'Re : Sondage : votre marque de lait préférée',
'Enrico', 'Le lait de chèvre');

insert into messages (id, id_parent, titre, auteur, texte)
values (10,8, 'Re : Sondage : votre marque de lait préférée',
'John', 'Je suis statisticien de formation et j''ai rien d''autre à faire');

insert into messages (id, id_parent, titre, auteur, texte)
values (11, NULL, 'Qui a vu le match de volley hier soir ?',
'Petrus', 'Si qq''un connaît le score, merci de nous le donner...');

insert into messages (id, id_parent, titre, auteur, texte)
values (12,10, 'Re : Sondage : votre marque de lait préférée', 'Fifi', 'Ok');

insert into messages (id, id_parent, titre, auteur, texte)
values (13,3, 'Re : Combien d''oeufs dans la pate à crêpes ?',
'Fifi', 'Oui c''est 2 par personne');

Ce qui nous donne le contenu suivant (par ordre chronologique de création des messages) :

 ID	ID_P	TITRE				 AUTEUR	HEURE
------	--------------------------------------------- ------------------
1	Combien d'oeufs dans la pate à crêpes ?		John	16:58:20
2	Sondage : votre marque de lait préférée		John	16:58:37
3 1	Re : Combien d'oeufs dans la pate à crêpes ?   Martine	16:58:51
4 3	C'est sûrement ça							  John	16:59:00
5 2	Re : Sondage : votre marque de lait préférée   Fifi	16:59:08
6 2	Re : Sondage : votre marque de lait préférée   Petrus	16:59:14
7 4	Re : C'est sûrement ça						 Martine	16:59:20
8 2	Re : Sondage : votre marque de lait préférée   Fifi	16:59:26
9 2	Re : Sondage : votre marque de lait préférée   Enrico	16:59:31
10 8	Re : Sondage : votre marque de lait préférée   John	16:59:45
11	Qui a vu le match de volley hier soir ?		Petrus	16:59:51
12 10	Re : Sondage : votre marque de lait préférée   Fifi	16:59:59
13 3	Re : Combien d'oeufs dans la pate à crêpes ?   Fifi	17:00:03

Ainsi : - les deux premiers messages sont des débuts de fil de discussion - le message ID=3 répond au message ID=1 car son ID_PARENT=1 - le message ID=13 répond au message ID=3 car son ID_PARENT=3 - etc...

Notre but est donc d'obtenir une hiérarchie de la forme :

ID=1
|-ID=3
| |-ID=4
| | |-ID=7
| |-ID=13
ID=2
|-ID=5
|-ID=6
|-ID=8
| |-ID=10
| | |-ID=12
|-ID=9
ID=11

Le lien entre un message et son parent est bien sûr fait avec les colonnes ID et ID_PARENT. Voici la syntaxe de l'ordre SQL permettant de récupérer la hiérarchie souhaitée :

===
SQL> select id, id_parent, titre
  2  from messages
  3  start with id_parent is null
  4  connect by id_parent = prior id;

	   ID ID_PARENT TITRE
--------- --------- --------------------------------------------------
		1		   Combien d'oeufs dans la pate à crêpes ?
		3		 1 Re : Combien d'oeufs dans la pate à crêpes ?
		4		 3 C'est sûrement ça
		7		 4 Re : C'est sûrement ça
	   13		 3 Re : Combien d'oeufs dans la pate à crêpes ?
		2		   Sondage : votre marque de lait préférée
		5		 2 Re : Sondage : votre marque de lait préférée
		6		 2 Re : Sondage : votre marque de lait préférée
		8		 2 Re : Sondage : votre marque de lait préférée
	   10		 8 Re : Sondage : votre marque de lait préférée
	   12		10 Re : Sondage : votre marque de lait préférée
		9		 2 Re : Sondage : votre marque de lait préférée
	   11		   Qui a vu le match de volley hier soir ?
13 ligne(s) sélectionnée(s).
===

Notre objectif est atteint : nous avons les messages dans le bon ordre. Une requête hiérarchique permet donc de trier des enregistrements en utilisant des notions d'arborescence inter-enregistrement.

La pseudo-colonne Level

Dans une hiérarchie, on peut avoir un élément A qui a pour enfant un élément B, qui lui-même a pour enfant un élément C, etc... On peut alors dire que l'élément C est au niveau n+2 par rapport au niveau n de l'élément A. Afin de mieux voir la profondeur de hiérarchie, nous allons utiliser la pseudo-colonne LEVEL, qui permet de savoir à quel niveau hiérarchique on se trouve :

===
SQL> select level, titre, auteur
  2  from  messages
  3  start with id_parent is null
  4  connect by id_parent = prior id;

	LEVEL TITRE											  AUTEUR
--------- -------------------------------------------------- ---------
		1 Combien d'oeufs dans la pate à crêpes ?			 John
		2 Re : Combien d'oeufs dans la pate à crêpes ?		Martine
		3 C'est sûrement ça								  John
		4 Re : C'est sûrement ça							 Martine
		3 Re : Combien d'oeufs dans la pate à crêpes ?		Fifi
		1 Sondage : votre marque de lait préférée			John
		2 Re : Sondage : votre marque de lait préférée	   Fifi
		2 Re : Sondage : votre marque de lait préférée	   Petrus
		2 Re : Sondage : votre marque de lait préférée	   Fifi
		3 Re : Sondage : votre marque de lait préférée	   John
		4 Re : Sondage : votre marque de lait préférée	   Fifi
		2 Re : Sondage : votre marque de lait préférée	   Enrico
		1 Qui a vu le match de volley hier soir ?			Petrus
13 ligne(s) sélectionnée(s).
===

Pour plus de clarté, nous allons faire précéder chaque titre d'un nombre d'espaces égal au level qui lui correspond. Cela génèrera une indentation du plus bel effet !

===
SQL>
  1  select id, id_parent, rpad(' ', level-1) || titre as titre, auteur
  2  from messages
  3  start with id_parent is null
  4  connect by id_parent = prior id;

 ID ID_PARENT	TITRE							AUTEUR
--- ---------	------------------------------------------------------	----------
  1		Combien d'oeufs dans la pate à crêpes ?			John
  3		 1	 Re : Combien d'oeufs dans la pate à crêpes ?		Martine
  4		 3	  C'est sûrement ça					John
  7		 4	   Re : C'est sûrement ça				Martine
 13		 3	  Re : Combien d'oeufs dans la pate à crêpes ?		Fifi
  2		Sondage : votre marque de lait préférée			John
  5		 2	 Re : Sondage : votre marque de lait préférée		Fifi
  6		 2	 Re : Sondage : votre marque de lait préférée		Petrus
  8		 2	 Re : Sondage : votre marque de lait préférée		Fifi
 10		 8	  Re : Sondage : votre marque de lait préférée		John
 12		10	   Re : Sondage : votre marque de lait préférée		Fifi
  9		 2	 Re : Sondage : votre marque de lait préférée		Enrico
 11		Qui a vu le match de volley hier soir ?			Petrus


13 ligne(s) sélectionnée(s).
===

Nous venons donc de voir à quoi peut servir une requête hiérarchique. Parmis les applications possible de cet outil puissant : - les forums avec fil de discussion (notre exemple) - hiérarchie d'un groupe de personnes (chefs de service - employés) - gestion de catégories et sous-catégories pour organiser des informations - ...

Quelques précisions sur la syntaxe des requêtes hiérarchiques

La clause START WITH permet d'indiquer la condition qui détermine quels enregistrements sont au niveau 1 (aucun enregistrement au-dessus d'eux dans la hiérarchie). Si on n'avait voulu lister que les fils de discussion initiés par John, avec leurs réponses, voici la requête qu'il aurait fallu exécuter :

===
SQL>
  1  select id, id_parent, rpad(' ', level-1) || titre as titre, auteur
  2  from messages
  3  start with id_parent is null and auteur = 'John'
  4* connect by id_parent = prior id
 ID ID_PARENT	TITRE							AUTEUR
--- ---------	------------------------------------------------------	----------
  1		Combien d'oeufs dans la pate à crêpes ?			John
  3		 1	 Re : Combien d'oeufs dans la pate à crêpes ?		Martine
  4		 3	  C'est sûrement ça					John
  7		 4	   Re : C'est sûrement ça				Martine
 13		 3	  Re : Combien d'oeufs dans la pate à crêpes ?		Fifi
  2		Sondage : votre marque de lait préférée			John
  5		 2	 Re : Sondage : votre marque de lait préférée		Fifi
  6		 2	 Re : Sondage : votre marque de lait préférée		Petrus
  8		 2	 Re : Sondage : votre marque de lait préférée		Fifi
 10		 8	  Re : Sondage : votre marque de lait préférée		John
 12		10	   Re : Sondage : votre marque de lait préférée		Fifi
  9		 2	 Re : Sondage : votre marque de lait préférée		Enrico
12 ligne(s) sélectionnée(s).
===

Le 13ème et dernier message n'a pas été sélectionné car il ne fait pas partie d'un fil de discussion initié par John. Les requêtes hiérarchiques sont donc non seulement un moyen de trier les enregistrements, mais aussi un moyen de sélectionner des enregistrements (même sans utilisation de la clause where).

La clause CONNECT BY permet d'indiquer la condition qui lie un enregistrement à son enregistrement père. "connect by id_parent = prior id" doit se lire "la relation père-fils entre deux enregistrements est définie par le fait que la colonne id_parent de l'enregistrement fils est égale à la colonne id de l'enregistrement père" (c'est le mot clé PRIOR qui indique que l'on fait référence au père).

Article écrit par Tittom

Ce document intitulé « Oracle - Les requêtes hiérarchiques » issu de Comment Ça Marche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.

Résultats pour Oracle Les requêtes hiérarchiques

Les jointures avec Oracle 8i (JOIN) (Résolu) Bonjour, Est-ce que quelqu'un peut me dire si Oracle 8i supporte les jointures avec INNER JOIN, LEFT JOIN et RIGHT JOIN ? J'ai une base ACCESS à faire migrer sous Oracle et j'ai 46 requêtes avec ce type de jointure. Une idée ou un outil... www.commentcamarche.net/forum/affich-1309111-les-jointures-avec-oracle-8i-join
SQL - Sous-requêtes Expression des sous-requêtes Effectuer une sous-requête consiste à effectuer une requête à l'intérieur d'une autre, ou en d'autres termes d'utiliser une requête afin d'en réaliser une autre (on entend parfois le terme de requêtes en... www.commentcamarche.net/contents/sql/sqlssreq.php3
Oracle - Le dictionnaire de données Présentation du dictionnaire de données Oracle Le dictionnaire de données Oracle représente le coeur de la base de données. Il s'agit d'un ensemble de tables systèmes contenant les informations relatives à la structure de la base de... www.commentcamarche.net/contents/oracle/oracdico.php3

Résultats pour Oracle Les requêtes hiérarchiques

Hiérarchisation et Sommaire automatique sous WordHiérarchisation et Sommaire automatique L’utilisation de la hiérarchisation sous Word permet de générer automatiquement un sommaire. De plus, il permet de simplifier les modifications de style et de mise en forme appliquées aux titres des... www.commentcamarche.net/faq/sujet-11911-hierarchisation-et-sommaire-automatique-sous-word
Connexion à une base Oracle en php1. Périmètre Cet article est un exemple de connexion à une base Oracle par le biais d'un script php. Cet article ne traite pas la configuration de votre serveur Oracle, et de votre client Oracle. Nous partons du principe que vous pouvez accéder à... www.commentcamarche.net/faq/sujet-123-connexion-a-une-base-oracle-en-php

Résultats pour Oracle Les requêtes hiérarchiques

[SQL][ORACLE] Liste des champs (Résolu)Bonjour à tous, J'ai un petit problème, j'aimerais construire une requête qui me retourne la liste des champs d'une table. Je peux le faire en MySQL : DESCRIBE nomTable; Je peux le faire en MSSQL : SELECT column_name as Field FROM... www.commentcamarche.net/forum/affich-2254690-sql-oracle-liste-des-champs
[PSQL] : pb avec requete imbriquee (Résolu)Bonjour, Je n'arrive pas à faire fonctionner une requete imbriquee qui utilise des alias de tables. Le premier et le dernier "SELECT" fonctionnent quand je les lance seuls. Le problème vient de la deuxième sous-requete où psql ne reconnait pas... www.commentcamarche.net/forum/affich-1731045-psql-pb-avec-requete-imbriquee
[oracle] comparaison d'heures (Résolu)Bonjour, Je travaille sous une base Oracle 8i. Je dispose d'un champs date du type 01/12/05 16:01:50. Il faut que je sélectionne tous les enregistrements dont la l'heure est comprise entre 8h00 et 8h30. Si quelqu'un connait la solution... www.commentcamarche.net/forum/affich-1953997-oracle-comparaison-d-heures

Résultats pour Oracle Les requêtes hiérarchiques

Oracle - La gestion de la mémoireL'utilisation de la mémoire par Oracle. Oracle fait un usage poussé de la mémoire physique (RAM, Random Access Memory) du serveur afin de fournir les meilleures performances possibles. Ainsi Oracle utilise la mémoire physique du serveur... www.commentcamarche.net/contents/oracle/oracmem.php3
SQL - JointuresExpression des jointures Une jointure (ou θ-jointure) est un produit cartésien de deux tables. On appelle équijointure une θ-jointure dont la qualification est une égalité entre deux colonnes. En SQL, l'expression d'une jointure se... www.commentcamarche.net/contents/sql/sqljoint.php3
PHP - Connexion à un annuaire LDAPIntroduction à LDAP PHP permet la connexion et l'envoi de requêtes sur un annuaire LDAP, c'est-à-dire un serveur permettant de stocker des informations de manière hiérarchique. Un serveur LDAP est conçu pour être capable de gérer les opérations... www.commentcamarche.net/contents/php/phpldap.php3