Salut à tous.
J'ai repris un vieux sujet (Publié le 18 avril 2004) de SQLPRO concernant la division relationnelle.
--> http://sqlpro.developpez.com/cours/divrelationnelle/
Comme à l'accoutumé, j'ai refais tous les exercices proposés dans ce cours.
J'ai pris le jeu d'essai, à savoir le jeu d'essai de base du §1 + l'ajout du §2-a)
et aussi celui du §2-b).
Code : Sélectionner tout - Visualiser dans une fenêtre à part INSERT INTO T_RAYON VALUES ('conserve')
Voici ce que donne les trois tables t_ville, t_rayon et t_entrepot.
Code : Sélectionner tout - Visualiser dans une fenêtre à part INSERT INTO T_ENTREPOT (VILLE_ETP, RAYON_RYN) VALUES ('MARSEILLE', 'boucherie')
On voie l'ajout dans la table t_rayon avec "id=5" et dans la table t_entrepot avec "id=18".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 -------------- SET AUTOCOMMIT = 0 -------------- -------------- START TRANSACTION -------------- -------------- DROP DATABASE IF EXISTS `base` -------------- -------------- CREATE DATABASE `base` DEFAULT CHARACTER SET `latin1` DEFAULT COLLATE `latin1_general_ci` -------------- -------------- DROP TABLE IF EXISTS `t_ville` -------------- -------------- CREATE TABLE `t_ville` ( `id` integer unsigned NOT NULL AUTO_INCREMENT primary key, `ville` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci` ROW_FORMAT=COMPRESSED -------------- -------------- INSERT INTO `t_ville` (`ville`) VALUES ('Paris'),('Anger'),('Lyon'),('Toulouse'),('Marseille') -------------- -------------- select * from t_ville -------------- +----+-----------+ | id | ville | +----+-----------+ | 1 | Paris | | 2 | Anger | | 3 | Lyon | | 4 | Toulouse | | 5 | Marseille | +----+-----------+ -------------- DROP TABLE IF EXISTS `t_rayon` -------------- -------------- CREATE TABLE `t_rayon` ( `id` integer unsigned NOT NULL AUTO_INCREMENT primary key, `rayon` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci` ROW_FORMAT=COMPRESSED -------------- -------------- INSERT INTO `t_rayon` (`rayon`) VALUES ('Conserve'),('Frais'),('Droguerie'),('Boisson') -------------- -------------- INSERT INTO `t_rayon` (`rayon`) VALUES ('Conserve') -------------- -------------- select * from t_rayon -------------- +----+-----------+ | id | rayon | +----+-----------+ | 1 | Conserve | | 2 | Frais | | 3 | Droguerie | | 4 | Boisson | | 5 | Conserve | +----+-----------+ -------------- DROP TABLE IF EXISTS `t_entrepot` -------------- -------------- CREATE TABLE `t_entrepot` ( `id` integer unsigned NOT NULL AUTO_INCREMENT primary key, `ville` varchar(255) NOT NULL, `rayon` varchar(255) NOT NULL, unique index `idx` (`ville`,`rayon`) ) ENGINE=InnoDB DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci` ROW_FORMAT=COMPRESSED -------------- -------------- INSERT INTO `t_entrepot` (`ville`,`rayon`) VALUES ('Paris', 'Boisson'), ('Paris', 'Frais'), ('Paris', 'Conserve'), ('Anger', 'Boisson'), ('Anger', 'Frais'), ('Anger', 'Droguerie'), ('Lyon', 'Boisson'), ('Lyon', 'Conserve'), ('Lyon', 'Droguerie'), ('Marseille', 'Boisson'), ('Marseille', 'Droguerie'), ('Marseille', 'Frais'), ('Marseille', 'Conserve'), ('Toulouse', 'Boisson'), ('Toulouse', 'Frais'), ('Toulouse', 'Droguerie'), ('Toulouse', 'Conserve') -------------- -------------- INSERT INTO `t_entrepot` (`ville`,`rayon`) VALUES ('Marseille', 'Boucherie') -------------- -------------- select * from t_entrepot order by id -------------- +----+-----------+-----------+ | id | ville | rayon | +----+-----------+-----------+ | 1 | Paris | Boisson | | 2 | Paris | Frais | | 3 | Paris | Conserve | | 4 | Anger | Boisson | | 5 | Anger | Frais | | 6 | Anger | Droguerie | | 7 | Lyon | Boisson | | 8 | Lyon | Conserve | | 9 | Lyon | Droguerie | | 10 | Marseille | Boisson | | 11 | Marseille | Droguerie | | 12 | Marseille | Frais | | 13 | Marseille | Conserve | | 14 | Toulouse | Boisson | | 15 | Toulouse | Frais | | 16 | Toulouse | Droguerie | | 17 | Toulouse | Conserve | | 18 | Marseille | Boucherie | +----+-----------+-----------+
J'ai pu retrouver les mêmes résultats et ma préférence se porte sur cette requête :
Par contre, je n'ai pas pu résoudre la requête utilisant le prédicat "exists", celle proposé au §5.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 select e.ville, count(e.ville) as nbre from t_entrepot as e where (e.ville, e.rayon) in ( select distinct v.ville, r.rayon from t_ville as v, t_rayon as r) group by e.ville having count(e.ville) = ( select count(distinct r.rayon) from t_rayon as r) -------------- +-----------+------+ | ville | nbre | +-----------+------+ | Marseille | 4 | | Toulouse | 4 | +-----------+------+
Voici ce que j'obtiens :
J'obtiens cinq lignes pour la ville de Marseille, celle où justement, nous avons ajouté la ligne ayant le rayon "boucherie" qui n'existe pas dans la table "t_rayon".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 select e1.ville from t_entrepot as e1 where not exists ( select 1 from t_rayon as r where not exists ( select 1 from t_entrepot as e2 where e2.ville = e1.ville and e2.rayon = r.rayon ) ) -------------- +-----------+ | ville | +-----------+ | Marseille | | Marseille | | Marseille | | Marseille | | Marseille | | Toulouse | | Toulouse | | Toulouse | | Toulouse | +-----------+
Inversement, la requête qui est basé sur le "in" fonctinne correctement.
Ici, nous avons bien 4 lignes pour la ville de Marseille et de Toulouse.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 select e1.ville from t_entrepot as e1 where e1.rayon in ( select e2.rayon from t_entrepot as e2 where e2.rayon not in ( select e3.rayon from t_entrepot as e3 where e3.rayon not in ( select r.rayon from t_rayon as r ) ) ) -------------- +-----------+ | ville | +-----------+ | Anger | | Anger | | Anger | | Lyon | | Lyon | | Lyon | | Marseille | | Marseille | | Marseille | | Marseille | | Paris | | Paris | | Paris | | Toulouse | | Toulouse | | Toulouse | | Toulouse | +-----------+
J'ai volontairement supprimé l'autre condition afin de faire apparaitre les tuples !
Voici ce qui a été supprimé des deux requêtes :
J'aimerai savoir pourquoi la requête avec le "exists" ne fonctionne pas ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 group by e1.ville having count(e1.ville) = ( select count(distinct rayon) from t_rayon );
@+
Partager