Précédent   Forum des professionnels en informatique > Bases de données > Langage SQL
Langage SQL Forum d'entraide sur le langage SQL et sur les questions liées à la conception de schéma (DDL). Cours SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 18/11/2011, 12h30   #1
Invité de passage
 
Homme
Développeur en systèmes embarqués
Inscription : novembre 2011
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Développeur en systèmes embarqués
Secteur : Industrie

Informations forums :
Inscription : novembre 2011
Messages : 3
Points : 0
Points : 0
Par défaut Select sur une représentation en arbre

Bonjour,

J'ai une table contenant des données (des machins dans mon exemple) et une table de liens utilisée pour représenter ces données en arbre.

Mon problème est de pouvoir sélectionner tous les descendants d'un même élément.

Exemple :

Création de la table machin :
Code :
1
2
3
4
5
6
CREATE TABLE machin
(
  id_machin serial NOT NULL,
  name_machin text NOT NULL,
  CONSTRAINT pk_id_machin PRIMARY KEY (id_machin)
)
Création de la table de lien :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE link_machin_machin
(
  id_machin_parent integer NOT NULL,
  id_machin_child integer NOT NULL,
  CONSTRAINT pk_link_machin_machin PRIMARY KEY (id_machin_parent, id_machin_child),
  CONSTRAINT link_machin_machin_id_machin_child_fkey FOREIGN KEY (id_machin_child)
      REFERENCES machin (id_machin) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE,
  CONSTRAINT link_machin_machin_id_machin_parent_fkey FOREIGN KEY (id_machin_parent)
      REFERENCES machin (id_machin) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE,
  CONSTRAINT link_machin_machin_id_machin_child_key UNIQUE (id_machin_child)
)
remplissage de la table machin :
Code :
1
2
3
4
5
6
7
8
9
10
11
INSERT INTO machin(id_machin,name_machin) VALUES (1, 'truc');
INSERT INTO machin(id_machin,name_machin) VALUES (2, 'bidule');
INSERT INTO machin(id_machin,name_machin) VALUES (3, 'trucnuche');
INSERT INTO machin(id_machin,name_machin) VALUES (4, 'chose');
INSERT INTO machin(id_machin,name_machin) VALUES (5, 'chouette');
INSERT INTO machin(id_machin,name_machin) VALUES (6, 'hibou');
INSERT INTO machin(id_machin,name_machin) VALUES (7, 'caillou');
INSERT INTO machin(id_machin,name_machin) VALUES (8, 'genou');
INSERT INTO machin(id_machin,name_machin) VALUES (9, 'bijou');
INSERT INTO machin(id_machin,name_machin) VALUES (10, 'joujou');
INSERT INTO machin(id_machin,name_machin) VALUES (11, 'pou');
remplissage de la table de lien :
Code :
1
2
3
4
5
6
7
8
9
INSERT INTO link_machin_machin VALUES (1, 2);
INSERT INTO link_machin_machin VALUES (1, 4);
INSERT INTO link_machin_machin VALUES (1, 5);
INSERT INTO link_machin_machin VALUES (5, 6);
INSERT INTO link_machin_machin VALUES (5, 7);
INSERT INTO link_machin_machin VALUES (7, 8);
INSERT INTO link_machin_machin VALUES (4, 10);
INSERT INTO link_machin_machin VALUES (4, 9);
INSERT INTO link_machin_machin VALUES (3, 11);
Ce qui doit donner un 2 arbres comme ceci :
Code :
1
2
3
4
5
6
7
8
1--2
|--4--10
|  |--9
|
|--5--6
   |--7--8
 
3--11
Le résultat attendu si je demande les descendants de l'element 1 :
Code :
1
2
3
4
5
6
7
8
9
10
11
 
id_machin     name_machin
-----------    -----------
2              bidule
4              chose
5              chouette
6              hibou
7              caillou
8              genou
9              bijou
10             joujou

Je ne sais pas du tout si il est possible de faire ça en une requête SQL.
Je ne suis pas développeur SQL et il y a surement des techniques standard pour ce problème qui m'échappent (j'ai bien essayé des trucs avec WITH RECURSIVE mais j'ai pas du comprendre comment l'utiliser correctement).

Note: J'utilise postgresql (8.4), je ne suis pas contre une fonction plpgsql recursive.

d'avance merci
ctxctx est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2011, 13h51   #2
Membre Expert
 
Inscription : mars 2005
Messages : 1 565
Détails du profil
Informations personnelles :
Âge : 29
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations forums :
Inscription : mars 2005
Messages : 1 565
Points : 2 178
Points : 2 178
Vous êtes sur la bonne voie. Un lien vers le cours d'SQLPro sur les CTE (mécanisme de SQL qui permet la récursivité notamment) : http://sqlpro.developpez.com/cours/s...ecursives/#LIV

Il y a un exemple de requête qui parcours un arbre modélisé par auto référence comme dans votre modèle.
vmolines est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2011, 14h10   #3
Membre Expert
 
Inscription : août 2008
Messages : 1 271
Détails du profil
Informations forums :
Inscription : août 2008
Messages : 1 271
Points : 1 929
Points : 1 929
En postgresql ça devrait donner ça (ça te donne un autre exemple):
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
  WITH recursive recursive_link (id_parent,name_machin, id_machin, hierlevel) AS (
SELECT NULL AS id_parent, name_machin, id_machin, 1
  FROM machin m
 WHERE id_machin = 1
 union ALL 
SELECT m1.id_machin, m1.name_machin, l.id_machin_child, rl.hierlevel + 1
  FROM machin m1
  JOIN link_machin_machin l ON l.id_machin_child = m1.id_machin
  JOIN recursive_link rl    ON rl.id_machin = l.id_machin_parent
)
SELECT id_machin, name_machin, hierlevel
  FROM recursive_link
 ORDER BY hierlevel, id_machin
Le test développé sous oracle :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
SQL>   WITH machin AS (
  2  SELECT 1 AS id_machin, 'truc' AS name_machin FROM dual union ALL
  3  SELECT 2             , 'bidule'              FROM dual union ALL
  4  SELECT 3             , 'trucnuche'           FROM dual union ALL
  5  SELECT 4             , 'chose'               FROM dual union ALL
  6  SELECT 5             , 'chouette'            FROM dual union ALL
  7  SELECT 6             , 'hibou'               FROM dual union ALL
  8  SELECT 7             , 'caillou'             FROM dual union ALL
  9  SELECT 8             , 'genou'               FROM dual union ALL
 10  SELECT 9             , 'bijou'               FROM dual union ALL
 11  SELECT 10            , 'joujou'              FROM dual union ALL
 12  SELECT 11            , 'pou'                 FROM dual
 13  ),
 14         link_machin_machin AS (
 15  SELECT 1 AS id_machin_parent, 2 AS id_machin_child FROM dual union ALL
 16  SELECT 1                    , 4          FROM dual union ALL
 17  SELECT 1                    , 5          FROM dual union ALL
 18  SELECT 5                    , 6          FROM dual union ALL
 19  SELECT 5                    , 7          FROM dual union ALL
 20  SELECT 7                    , 8          FROM dual union ALL
 21  SELECT 4                    , 10         FROM dual union ALL
 22  SELECT 4                    , 9          FROM dual union ALL
 23  SELECT 3                    , 11         FROM dual
 24  ),
 25         recursive_link (id_parent,name_machin, id_machin, hierlevel) AS (
 26  SELECT NULL AS id_parent, name_machin, id_machin, 1
 27    FROM machin m
 28   WHERE id_machin = 1
 29   union ALL
 30  SELECT m1.id_machin, m1.name_machin, l.id_machin_child, rl.hierlevel + 1
 31    FROM machin m1
 32    JOIN link_machin_machin l ON l.id_machin_child = m1.id_machin
 33    JOIN recursive_link rl    ON rl.id_machin = l.id_machin_parent
 34  )
 35  SELECT id_machin, name_machin, hierlevel
 36    FROM recursive_link
 37   ORDER BY hierlevel, id_machin
 38  /
 
 ID_MACHIN NAME_MACH  HIERLEVEL
---------- --------- ----------
         1 truc               1
         2 bidule             2
         4 chose              2
         5 chouette           2
         6 hibou              3
         7 caillou            3
         9 bijou              3
        10 joujou             3
         8 genou              4
 
9 rows selected.
 
SQL>
skuatamad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2011, 14h51   #4
Rédacteur/Modérateur

 
Avatar de SQLpro
 
Homme Frédéric BROUARD
Expert SGBDR & SQL
Inscription : mai 2002
Messages : 10 959
Détails du profil
Informations personnelles :
Nom : Homme Frédéric BROUARD
Localisation : France

Informations professionnelles :
Activité : Expert SGBDR & SQL
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 10 959
Points : 17 791
Points : 17 791
Sauf que votre modèle est incorrect. Vous avez créé une table de liens, alors que vous voulez représenter un arbre.
Il aurait suffit de mettre une auto référence.
Dans votre modèle, vous n'avez pas modélisé un arbre mais un graphe au sens mathématique du terme (réseau).

Donc vos requêtes sont incorrecte compte tenu du modèle et en sus vous pouvez avoir des cycles !

A +
__________________
Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
Site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
Blog SQL, SQL Server, modélisation données : http://blog.developpez.com/sqlpro
http://www.sqlspot.com : modélisation, conseils, audit, optimisation, formation
* * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * *
SQLpro est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2011, 14h57   #5
Invité de passage
 
Homme
Développeur en systèmes embarqués
Inscription : novembre 2011
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Développeur en systèmes embarqués
Secteur : Industrie

Informations forums :
Inscription : novembre 2011
Messages : 3
Points : 0
Points : 0
Par défaut Ma solution avec WITH RECURSIVE

Merci vmoline, en fait j'avais survolé WITH RECURSIVE (et veinement tenté l'écriture de fonction pglsql) alors que WITH RECURSIVE semble bien être la solution.

Donc j'ai fait comme ceci (pour recupérer tout les descendant de l'id 1) :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
WITH RECURSIVE tree(id) AS
(
	SELECT id_machin
	FROM   machin
	WHERE  id_machin = 1
	UNION ALL
	SELECT id_machin_child
	FROM   link_machin_machin lmm
		INNER JOIN tree t
		ON t.id = lmm.id_machin_parent
)
SELECT * FROM machin WHERE id_machin IN (
	SELECT * FROM tree
) ORDER BY id_machin
qui me retourne :
Code :
1
2
3
4
5
6
7
8
9
10
11
id_machin		name_machin
---------		-----------
1			"truc"
2			"bidule"
4			"chose"
5			"chouette"
6			"hibou"
7			"caillou"
8			"genou"
9			"bijou"
10			"joujou"
alors oui, ça rajoute le machin d'id 1, mais en fait c'est ce que je voulais.

merci skuatamad, mais la première requête (dans postgres 8.4) me dit :
Code :
1
2
3
4
5
ERREUR:  dans la requête récursive « recursive_link », la colonne 1 a le type text dans le terme non
récursif mais le type global integer
LIGNE 2 : SELECT NULL AS id_parent, name_machin, id_machin, 1
                 ^
ASTUCE : Convertit la sortie du terme non récursif dans le bon type.
et je ne sais pas ce qu'il appelle "le bon type".

Merci pour vos réponses si rapides
ctxctx est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2011, 15h09   #6
Membre Expert
 
Avatar de pacmann
 
Homme Pacman Pacman
Business analyst
Inscription : juin 2004
Messages : 1 417
Détails du profil
Informations personnelles :
Nom : Homme Pacman Pacman
Âge : 31
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Business analyst
Secteur : Finance

Informations forums :
Inscription : juin 2004
Messages : 1 417
Points : 2 309
Points : 2 309
Salut !

En fait, il considère que NULL est de type text, or il faut que ça matche avec l'id.

Tente peut-être de remplacer par CAST(NULL AS INTEGER) ou un truc du genre...
__________________

(c'est ma photo)
Paku, Paku !
Pour les jeunes incultes : non, je ne suis pas un pokémon...

Le pacblog : http://pacmann.over-blog.com/
pacmann est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2011, 15h12   #7
Membre Expert
 
Inscription : mars 2005
Messages : 1 565
Détails du profil
Informations personnelles :
Âge : 29
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations forums :
Inscription : mars 2005
Messages : 1 565
Points : 2 178
Points : 2 178
Pour revenir sur mon conseil, il n'est pas tout à fait bon puisque votre modèle (que je n'ai pas lu en m'empressant de répondre) n'utilise pas l'auto référence comme l'a justement souligné SQLPro.
vmolines est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2011, 15h14   #8
Membre Expert
 
Inscription : août 2008
Messages : 1 271
Détails du profil
Informations forums :
Inscription : août 2008
Messages : 1 271
Points : 1 929
Points : 1 929
Et comme ça ?
Code :
SELECT cast(NULL AS integer) AS id_parent,
Sinon je suis d'accord avec sqlpro, la colonne parent_id devrait être intégrée à la table machin.
skuatamad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2011, 15h25   #9
Invité de passage
 
Homme
Développeur en systèmes embarqués
Inscription : novembre 2011
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Développeur en systèmes embarqués
Secteur : Industrie

Informations forums :
Inscription : novembre 2011
Messages : 3
Points : 0
Points : 0
Citation:
Envoyé par SQLpro Voir le message
Sauf que votre modèle est incorrect. Vous avez créé une table de liens, alors que vous voulez représenter un arbre.
Il aurait suffit de mettre une auto référence.
Dans votre modèle, vous n'avez pas modélisé un arbre mais un graphe au sens mathématique du terme (réseau).

Donc vos requêtes sont incorrecte compte tenu du modèle et en sus vous pouvez avoir des cycles !

A +
Oui, c'est vrai. D’ailleurs j'ai oublié de dire que je désapprouve/déconseille vivement ce modèle.
Mais bon maintenant que la base est faite il faut l'utiliser comme elle est...
En fait l'application qui insère des données dans la table le fait de sorte que les données forment bien un arbre (donc pas de cycles).
C'est pas idéal et l'idée de départ s'est transformée en mauvaise conception.
Il est prévu (et je me battrai pour) de changer ce modèle lors de la prochaine version majeure du soft.

pacmann+skuatamad : avec CAST(NULL AS INTEGER) ça passe effectivement, merci
ctxctx est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/11/2011, 04h28   #10
Expert Confirmé Sénior

 
Avatar de fsmrel
 
Spécialiste en bases de données
Inscription : septembre 2006
Messages : 2 884
Détails du profil
Informations professionnelles :
Activité : Spécialiste en bases de données
Secteur : Conseil

Informations forums :
Inscription : septembre 2006
Messages : 2 884
Points : 5 125
Points : 5 125
Bonsoir,


La discussion est marquée résolue, mais je souhaite quand même intervenir, car ce qui a été dit hier est parfois contestable et les conclusions un peu hâtives.


1) L’utilisation de l’auto-référence n’interdit pas les cycles. Exemple :

Code SQL :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE T
(      PieceId            INT            NOT NULL
     , PieceNom           VARCHAR(48)    NOT NULL
     , PieceParentId      INT
    , CONSTRAINT T_PK PRIMARY KEY (PieceId)
    , CONSTRAINT T_FK FOREIGN KEY (PieceParentId) REFERENCES T (PieceId)) ;
 
INSERT INTO T VALUES (1, 'Pièce1', NULL) ;
INSERT INTO T VALUES (2, 'Pièce2', 1) ;
INSERT INTO T VALUES (3, 'Pièce3', 2) ;
 
UPDATE T SET PieceParentId = 3 WHERE PieceId = 1 ;
 
SELECT * FROM T ;
=>

Code :
1
2
3
4
PieceId    PieceNom    PieceParentId
      1    Pièce1                  3
      2    Pièce2                  1
      3    Pièce3                  2

2) L’utilisation de l’auto-référence n’exclut pas non plus la possibilité de représenter des graphes. Exemple :

Code SQL :
1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE T
(      PieceId1            INT            NOT NULL
     , PieceId2            INT            NOT NULL           
    , CONSTRAINT T_PK PRIMARY KEY (PieceId1, PieceId2)
    , CONSTRAINT T_FK FOREIGN KEY (PieceId1, PieceId2) REFERENCES T (PieceId1, PieceId2)) ;
 
INSERT INTO T VALUES (1, 1) ;
INSERT INTO T VALUES (2, 2) ;
INSERT INTO T VALUES (3, 1) ;
INSERT INTO T VALUES (3, 2) ;
INSERT INTO T VALUES (4, 3) ;
 
SELECT * FROM T ;
=>
Code :
1
2
3
4
5
6
PieceId1    PieceId2
       1           1
       2           2
       3           1
       3           2
       4           3
La pièce 3 a deux parentes directes, les pièces 1 et 2.


3) Aux cycles près toujours possibles, la table de liens définie par ctxctx n’autorise que des structures arborescentes. Ceci est la conséquence de la présence de la clé candidate {id_machin_child} :
CONSTRAINT link_machin_machin_id_machin_child_key UNIQUE (id_machin_child)
La seule modification à apporter consiste donc à évacuer la clé primaire actuelle {id_machin_parent, id_machin_child} de la table link_machin_machin en la remplaçant par le singleton {id_machin_child}.


4) L’utilisation de l’auto-référence est en fait intéressante pour les opérations de suppression en cascade (si le SGBD le permet), sinon il faut mettre en œuvre de la programmation pour pallier (selon la représentation de ctxctx, l’utilisation de la clause ON DELETE CASCADE permet seulement de supprimer les liens entre un enfant et son parent).
__________________
_
Faites simple, mais pas plus simple ! (A. Einstein)
E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
=> La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

__________________

Bases de données relationnelles et normalisation : de la première à la sixième forme normale (Bonne lecture !)
fsmrel est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 20/11/2011, 02h22   #11
Expert Confirmé Sénior

 
Avatar de fsmrel
 
Spécialiste en bases de données
Inscription : septembre 2006
Messages : 2 884
Détails du profil
Informations professionnelles :
Activité : Spécialiste en bases de données
Secteur : Conseil

Informations forums :
Inscription : septembre 2006
Messages : 2 884
Points : 5 125
Points : 5 125
Bonsoir,


En complément : un exemple d’instructions (SQL Server) pour supprimer un noeud et ses descendants quand il n'y a pas auto-référence, c'est-à-dire dans le style de ctxctx. Les cracks de SQL ne manquement pas d’améliorer ce modeste essai.

Création des tables PIECE et NOMENCLATURE à la façon de ctxctx (noter la clause ON DELETE CASCADE sans laquelle la suppression ensembliste échoue) :

Code SQL :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE PIECE (
       PieceId            INT                  NOT NULL
     , pieceLibelle       VARCHAR(64)          NOT NULL
   , CONSTRAINT PIECE_PK PRIMARY KEY  (PieceId)
) ;
 
CREATE TABLE NOMENCLATURE (
       PieceId           INT       NOT NULL     
     , PieceParenteId    INT       NOT NULL     
   , CONSTRAINT NOMENCLATURE_PK PRIMARY KEY (PieceId)  
   , CONSTRAINT NOMENCLATURE_IS_PIECE_ENFANT_FK FOREIGN KEY (PieceId)
                REFERENCES PIECE (PieceId) ON DELETE CASCADE
   , CONSTRAINT NOMENCLATURE_PARENT_FK FOREIGN KEY (PieceParenteId)
                REFERENCES PIECE (PieceId) ON DELETE NO ACTION 
) ;

Création d’une fonction permettant de récupérer un nœud et ses descendants :

Code SQL :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE FUNCTION DESCENDANCE_FONCTION (@PieceId INT)
    RETURNS @Resultat TABLE (PieceId INT NOT NULL)
    AS 
        BEGIN
           WITH DESCENDANCE (PieceId) AS
               ((SELECT   PieceId
                 FROM     PIECE  
                 WHERE    PieceId = @PieceId)
                 UNION ALL
                (SELECT   x.PieceId 
                 FROM     NOMENCLATURE AS x JOIN DESCENDANCE AS y
                          ON y.PieceId = x.PieceParenteId))
           INSERT INTO @Resultat 
                      SELECT PieceId
                      FROM   DESCENDANCE ;
           RETURN 
        END ;

Suppression en cascade des liens qu’entretient la pièce 3 avec ses descendantes :

Code SQL :
1
2
3
DELETE FROM  NOMENCLATURE
       WHERE PieceId IN (SELECT  PieceId
                           FROM    DESCENDANCE_FONCTION(3)) ;

Jeu d’essai (table PIECE) :

Code SQL :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
INSERT INTO PIECE VALUES (1, 'Pièce 01') ; 
INSERT INTO PIECE VALUES (2, 'Pièce 02') ; 
INSERT INTO PIECE VALUES (3, 'Pièce 03') ; 
INSERT INTO PIECE VALUES (4, 'Pièce 04') ; 
INSERT INTO PIECE VALUES (5, 'Pièce 05') ; 
INSERT INTO PIECE VALUES (6, 'Pièce 06') ; 
INSERT INTO PIECE VALUES (7, 'Pièce 07') ; 
INSERT INTO PIECE VALUES (8, 'Pièce 08') ; 
INSERT INTO PIECE VALUES (9, 'Pièce 09') ; 
INSERT INTO PIECE VALUES (10, 'Pièce 10') ; 
INSERT INTO PIECE VALUES (11, 'Pièce 11') ; 
INSERT INTO PIECE VALUES (12, 'Pièce 12') ;  
INSERT INTO PIECE VALUES (13, 'Pièce 13') ;  
INSERT INTO PIECE VALUES (14, 'Pièce 14') ; 
INSERT INTO PIECE VALUES (15, 'Pièce 15') ;

Jeu d’essai (table NOMENCLATURE) :

Code SQL :
1
2
3
4
5
6
7
8
9
10
11
INSERT INTO NOMENCLATURE VALUES (3, 1)   ;  
INSERT INTO NOMENCLATURE VALUES (5, 3)   ; 
INSERT INTO NOMENCLATURE VALUES (7, 5)   ;  
INSERT INTO NOMENCLATURE VALUES (8, 15)  ; 
INSERT INTO NOMENCLATURE VALUES (9, 2)   ; 
INSERT INTO NOMENCLATURE VALUES (10, 1)  ; 
INSERT INTO NOMENCLATURE VALUES (12, 9)  ;  
INSERT INTO NOMENCLATURE VALUES (4, 9)   ;  
INSERT INTO NOMENCLATURE VALUES (13, 12) ;  
INSERT INTO NOMENCLATURE VALUES (15,  3) ; 
INSERT INTO NOMENCLATURE VALUES (6,  15) ;

Nomenclature avant suppression des liens avec la pièce 3 :


Après suppression :
__________________
_
Faites simple, mais pas plus simple ! (A. Einstein)
E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
=> La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

__________________

Bases de données relationnelles et normalisation : de la première à la sixième forme normale (Bonne lecture !)
fsmrel est déconnecté   Envoyer un message privé Réponse avec citation 30
Vieux 21/11/2011, 11h31   #12
Membre Expert
 
Avatar de pacmann
 
Homme Pacman Pacman
Business analyst
Inscription : juin 2004
Messages : 1 417
Détails du profil
Informations personnelles :
Nom : Homme Pacman Pacman
Âge : 31
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Business analyst
Secteur : Finance

Informations forums :
Inscription : juin 2004
Messages : 1 417
Points : 2 309
Points : 2 309
Salut,

Juste une question : les contraintes ne sont-elles pas validées "en bloc" pour une même requête SQL ?
__________________

(c'est ma photo)
Paku, Paku !
Pour les jeunes incultes : non, je ne suis pas un pokémon...

Le pacblog : http://pacmann.over-blog.com/
pacmann est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 13h47   #13
Expert Confirmé Sénior

 
Avatar de fsmrel
 
Spécialiste en bases de données
Inscription : septembre 2006
Messages : 2 884
Détails du profil
Informations professionnelles :
Activité : Spécialiste en bases de données
Secteur : Conseil

Informations forums :
Inscription : septembre 2006
Messages : 2 884
Points : 5 125
Points : 5 125
Bonjour vigilant pacmann,


Citation:
Envoyé par pacmann Voir le message
Juste une question : les contraintes ne sont-elles pas validées "en bloc" pour une même requête SQL ?
Certes, et c’est ce qui différencie les SGBD relationnels (tels que DB2 ou SQL Server) de leurs prédécesseurs avec lesquels s’il y avait échec (viol d’une contrainte), on avait droit à un code-retour avec en prime, par exemple dans le cas d’IMS/DL1 un message complémentaire célèbre en son temps et redoutable : « Unpredictable result »...

On est donc désormais dans le paradigme du « tout ou rien ». Si un « NO ACTION » joue son rôle, en cas d’infraction de notre part le résultat d’une requête SQL de suppression (ou de modification) est annulée en bloc, ce qui est tout de même plus rassurant qu’avec IMS/DL1. Mais l’adhésion des constructeurs de SGBD au paradigme peut les conduire à certaines options mal venues dans la mise en œuvre, je vous renvoie à ce sujet au message dans lequel je rappelle que les pères de DB2 et SQL Server ont fait des choix différents et qui sont infondés si l’on suit Chris Date qui place le niveau « en bloc » à un niveau supérieur, cf. Database Explorations, Essays on The Third Manifesto and Related Topics, page 224.
__________________
_
Faites simple, mais pas plus simple ! (A. Einstein)
E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
=> La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

__________________

Bases de données relationnelles et normalisation : de la première à la sixième forme normale (Bonne lecture !)
fsmrel est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 01h53   #14
Expert Confirmé Sénior

 
Avatar de fsmrel
 
Spécialiste en bases de données
Inscription : septembre 2006
Messages : 2 884
Détails du profil
Informations professionnelles :
Activité : Spécialiste en bases de données
Secteur : Conseil

Informations forums :
Inscription : septembre 2006
Messages : 2 884
Points : 5 125
Points : 5 125
Bonsoir,

Citation:
Envoyé par pacmann Voir le message
Juste une question : les contraintes ne sont-elles pas validées "en bloc" pour une même requête SQL ?
Je ne sais pas si en fait votre question a à voir avec la clause 'NO ACTION' de la contrainte NOMENCLATURE_PARENT_FK, mais je vais faire comme si. Après réflexion, je modifie mon message du 20/11/2011.

Au lieu de :

Suppression de la pièce 3 et de ses descendants :
Code :
1
2
3
DELETE FROM PIECE
       WHERE PieceId IN (SELECT  PieceId
                           FROM    DESCENDANCE_FONCTION(3)) ;
Je propose :

Suppression en cascade des liens qu’entretient la pièce 3 avec ses descendantes :

Code :
1
2
3
DELETE FROM NOMENCLATURE
       WHERE PieceId IN (SELECT  PieceId
                           FROM    DESCENDANCE_FONCTION(3)) ;
En effet, je constate que la requête fonctionne, mais après tout, il n’y a pas de raison pour qu’une de ses descendantes 5, 6, 7, 8, 15 ne réagisse pas.

Si en plus on veut aussi supprimer les pièces 3, 5, 6, 7, 8, 15, il est préférable de supprimer d’abord les liens directement dans la table NOMENCLATURE comme on vient de le faire et seulement après de supprimer les pièces :

Code SQL :
1
2
3
4
5
6
7
DECLARE @tmp TABLE (PieceId INT) ;
 
INSERT INTO @tmp SELECT PieceId FROM DESCENDANCE_FONCTION(3) ;
 
DELETE FROM NOMENCLATURE WHERE PieceId IN (SELECT PieceId FROM @tmp) ;
 
DELETE FROM PIECE WHERE PieceId IN (SELECT PieceId FROM @tmp) ;
N.B. La table @tmp n’est là que pour gagner un peu de temps dans cette opération.
__________________
_
Faites simple, mais pas plus simple ! (A. Einstein)
E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
=> La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

__________________

Bases de données relationnelles et normalisation : de la première à la sixième forme normale (Bonne lecture !)
fsmrel est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 12h26   #15
Membre Expert
 
Avatar de pacmann
 
Homme Pacman Pacman
Business analyst
Inscription : juin 2004
Messages : 1 417
Détails du profil
Informations personnelles :
Nom : Homme Pacman Pacman
Âge : 31
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Business analyst
Secteur : Finance

Informations forums :
Inscription : juin 2004
Messages : 1 417
Points : 2 309
Points : 2 309
Salut,

Mais ma remarque concernait effectivement juste :
Citation:
(noter la clause ON DELETE CASCADE sans laquelle la suppression ensembliste échoue)
Et en fait j'avais mal lu votre solution
Je pensais qu'il s'agissait d'une solution à une table avec auto-référence... du coup je me disais qu'il serait étrange que la validation de la requête dépende en quelque sorte du plan d'exécution (si on supprime les fils d'abord donc en triant par niveau, pas de problème).

J'aime bien votre version revue (sûrement parce que je suis pas fan de cascades ).

C'est peut-être juste une question de goût, mais une vue n'aurait-elle pas fait autant l'affaire qu'une fonction retournant une table (sans changer le reste de la mécanique) ?
__________________

(c'est ma photo)
Paku, Paku !
Pour les jeunes incultes : non, je ne suis pas un pokémon...

Le pacblog : http://pacmann.over-blog.com/
pacmann est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 16h27   #16
Expert Confirmé Sénior

 
Avatar de fsmrel
 
Spécialiste en bases de données
Inscription : septembre 2006
Messages : 2 884
Détails du profil
Informations professionnelles :
Activité : Spécialiste en bases de données
Secteur : Conseil

Informations forums :
Inscription : septembre 2006
Messages : 2 884
Points : 5 125
Points : 5 125
Par défaut Fonction ou vue ?

Ave pacmann,

Citation:
Envoyé par pacmann Voir le message
une vue n'aurait-elle pas fait autant l'affaire qu'une fonction retournant une table (sans changer le reste de la mécanique) ?
Ça serait sympa de pouvoir utiliser une vue, mais je ne pense pas qu'on puisse lui passer un paramètre, en l’occurrence PieceId = 3 :

Code SQL :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE VIEW DESCENDANCE (PieceId) AS    
WITH DESCENDANCE (PieceId) AS
( 
 (
      SELECT   PieceId
      FROM     PIECE  
      WHERE    PieceId = ???? -- Comment passer la valeur par paramètre ?
 )
    UNION ALL
     (SELECT   x.PieceId 
      FROM     NOMENCLATURE AS x JOIN DESCENDANCE AS y
                     ON y.PieceId = x.PieceParenteId
 )
)
SELECT DISTINCT PieceId FROM  DESCENDANCE ;
Quel est votre avis ?
__________________
_
Faites simple, mais pas plus simple ! (A. Einstein)
E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
=> La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

__________________

Bases de données relationnelles et normalisation : de la première à la sixième forme normale (Bonne lecture !)
fsmrel est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 17h28   #17
Membre Expert
 
Avatar de pacmann
 
Homme Pacman Pacman
Business analyst
Inscription : juin 2004
Messages : 1 417
Détails du profil
Informations personnelles :
Nom : Homme Pacman Pacman
Âge : 31
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Business analyst
Secteur : Finance

Informations forums :
Inscription : juin 2004
Messages : 1 417
Points : 2 309
Points : 2 309
Effectivement, je suis à côté de la plaque

On pourrait bien créer la vue sur sans pieceid et en ajoutant une colonne "root", puis filtrer sur root.
Par contre, je pense que l'optimiseur n'arrivera pas à "push" le prédicat et que ça fait construire l'arbre en entier à chaque fois...

J'essaierai de plus répondre sans réfléchir, c'est nul
__________________

(c'est ma photo)
Paku, Paku !
Pour les jeunes incultes : non, je ne suis pas un pokémon...

Le pacblog : http://pacmann.over-blog.com/
pacmann est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/11/2011, 15h45   #18
Rédacteur/Modérateur

 
Avatar de SQLpro
 
Homme Frédéric BROUARD
Expert SGBDR & SQL
Inscription : mai 2002
Messages : 10 959
Détails du profil
Informations personnelles :
Nom : Homme Frédéric BROUARD
Localisation : France

Informations professionnelles :
Activité : Expert SGBDR & SQL
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 10 959
Points : 17 791
Points : 17 791
Citation:
Envoyé par fsmrel Voir le message
Bonjour vigilant pacmann,

Certes, et c’est ce qui différencie les SGBD relationnels (tels que DB2 ou SQL Server) de leurs prédécesseurs avec lesquels s’il y avait échec (viol d’une contrainte), on avait droit à un code-retour avec en prime, par exemple dans le cas d’IMS/DL1 un message complémentaire célèbre en son temps et redoutable : « Unpredictable result »...
Le problème est que PostGreSQL et pire encore, MySQL ne sont pas des SGBD relationnels !!!
En effet, la mise à jour globale et par requête d'une colonne UNIQUE (PK par exemple), n'est toujours pas supportée ni par l'un ni par l'autre car les contraintes sont vérifiées lignes par ligne !

Pour PG il existe une solution de contournement (je sais pas si elle est encore en béta ou déjà en prod) pour différer la contrainte au niveau de la finalisation de la transaction....

A +
__________________
Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
Site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
Blog SQL, SQL Server, modélisation données : http://blog.developpez.com/sqlpro
http://www.sqlspot.com : modélisation, conseils, audit, optimisation, formation
* * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * *
SQLpro est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 14h03.


 
 
 
 
Partenaires

Hébergement Web