Ajout, suppression et modification des données 1 Valeurs NULL En SQL, la valeur NULL est une constante particulière qui indique que l information est manquante. Le comportement de NULL diffère un peu des autres valeurs. On teste si une colonne a la valeur NULL avec col IS NULL. On utilise col IS NOT NULL pour tester si une colonne n est pas NULL. Les valeurs NULL sont traitées différemment des autres valeurs par les opérateurs booléens, arithmétiques ou d agrégations. Par exemple, (NULL OR False) ne renvoie ni vrai ni faux mais NULL. 1. Les requêtes SELECT FROM t et SELECT FROM t WHERE col<0 or col>=0 renvoient-telles la même valeur? Pourquoi? Si la colonne col peut prendre la valeur NULL (peut ne pas être renseignée), les résultats peuvent être différents. La seconde requête est équivalente à SELECT FROM t WHERE col IS NOT NULL. 2. Les requêtes SELECT COUNT(capital) FROM world.country et SELECT COUNT(countrycode) FROM world.country renvoient-t-elles la même valeur? Non. La première renvoie 232, la seconde renvoie 239. L aggrégation COUNT ne compte que les valeurs non nulles. On obtient le même résultat que la première requête avec SELECT COUNT(countrycode) FILTER (WHERE capital IS NOT NULL) FROM world.country. 3. Quels sont les pays dont l espérance de vie ou le PNB est inconnu? Les 17 pays peuvent être listés par SELECT countrycode FROM world.country WHERE lifeexpectancy IS NULL OR gnp IS NULL. Ce sont en fait les pays ou lifeexpectancy n est pas renseigné et où la colonne gnp vaut 0. 4. Combien de pays n ont pas de capitale? Nous avons déjà répondu à la question : 239 232 = 7. Par exemple avec : SELECT COUNT(countrycode) FILTER (WHERE capital IS NULL) FROM world.country 5. Quels sont les pays dont toutes les villes ont moins de 1000 habitants? Attention, il y a des pays qui n ont pas de villes et qui, logiquement, respectent cette condition. En calcul relationnel cela donne { nom : co country(co) co.name_country = nom ( ci city(ci) ci.countrycode = co.countrycode )} ci.population_city > 1000 La requête suivante ne répond pas à la question 1
SELECT name country FROM world. country NATURAL JOIN world. c i t y WHERE c i. p o p u l a t i o n c i t y < 1000 ; c i La requête suivant répond à la question SELECT name country FROM world. country co WHERE NOT EXISTS ( SELECT FROM world. c i t y c i WHERE c i. countrycode=co. countrycode AND c i. p o p u l a t i o n c i t y >1000) ; C est la traduction directe de la requête exprimée en calcul relationnel. 6. Combien de clients de sakila ne vivent pas en France? Attention, il se pourrait que certains clients n aient pas spécifié leur adresse (champ address_id est NULL). En fait le schéma complet de customer spécifie que address_id ne peut être NULL. On peut donc répondre par SELECT COUNT( cu. customer id ) FROM s a k i l a. customer cu NATURAL JOIN s a k i l a. address NATURAL JOIN s a k i l a. c i t y NATURAL JOIN s a k i l a. country co WHERE co. country <> France ; 7. Quels sont les films dont tous les exemplaires DVD n ont jamais été retournés? Cette question est de même forme que la question 5. On peut la traduire en quels sont les films dont il n existe pas d exemplaire DVD retourné. Cela comprend les films qui n ont jamais été loués. SELECT t i t l e FROM s a k i l a. f i l m f i WHERE NOT EXISTS ( SELECT FROM s a k i l a. i n v e n t o r y inv NATURAL JOIN s a k i l a. r e n t a l re WHERE inv. f i l m i d = f i. f i l m i d AND re. r e t u r n d a t e IS NOT NULL ) ; Les 42 films listés sont en fait ceux pour lesquels il n existe pas de DVD dans l inventaire. 2 INSERT INTO, UPDATE et DELETE On rappelle que INSERT INTO permet d insérer des données dans une table, DELETE de les supprimer et UPDATE de modifier certaines lignes. Quel effet ont les requêtes suivantes sur la base de données? 1. INSERT INTO world.country (name country, countrycode) VALUES ( Atlantide, ATL ); Ajoute le pays dont le nom est Atlantide et le code est ATL. Les colonnes dont la valeur n a pas été spécifiée prennent la valeur NULL (ou possiblement une valeur par défaut dépendant de la table). 2
En fait, il ne se passe rien, car de nombreuses colonnes de world.country sont NOT NULL. Il se passe quelque chose si on travaille sur une copie de country où les contraintes NOT NULL n ont pas été spécifiées. 2. INSERT INTO sakila.country (country) VALUES (SELECT name country FROM world.country); Insère les noms pays de la table world.country dans la table sakila.country. Les colonnes country_id et lastupdate_country sont renseignées automatiquement. 3. DELETE FROM world.city; Il ne se passe rien, car une suppression violerait les contraintes référentielles entre les tables city et country (une ville doit se situer dans un pays). 4. DELETE FROM world.country WHERE countrycode!= (SELECT countrycode FROM world.city WHERE id=capital); Supprimerait les pays de world.country dont la capitale indiquée n est pas dans ce pays. 5. UPDATE world.country SET lifeexpectancy = NULL WHERE population country = 0; Met le champ lifeexpectancy à NULL si la population du pays est 0. 6. WITH LastRental AS (SELECT customer id as c, MAX( r e n t a l d a t e ) as d FROM s a k i l a. r e n t a l GROUP BY customer id ) DELETE FROM s a k i l a. customer WHERE EXTRACT( days FROM NOW( ) (SELECT d FROM LastRental WHERE customer id = c ) ) > 3 6 5 ; Supprime les clients inactifs depuis plus d un an. 3 CREATE TABLE CREATE TABLE table name ( column name1 type, column name2 type,... ) ; crée une nouvelle table dans la base de données avec les colonnes spécifiées. Par exemple CREATE TABLE livre(titre VARCHAR(200), auteur VARCHAR(100), resume TEXT, prix INT);. On peut remplir la table avec le résultat d une requête au moment de son initialisation avec CREATE TABLE name(col1 type,...,colk type) AS requete. En cas d erreur, on peut supprimer une table avec la commande DROP TABLE name. 1. Proposez une façon de copier une table dans une autre. 3
Pour constituer une copie de world.country CREATE TABLE e n t i d. country AS SELECT FORM world. country ; 4 TP Toutes les opérations modifiant la base de données nécessitent d avoir les droits d écritures sur la table ou le schéma concernés. Vous n avez pas les droits d écriture dans les schémas sakila, world etc. mais vous avez les droits d écriture dans votre schéma personnel (votre identifiant ENT). On va créer une table CountryCapital dans votre schéma qui doit pouvoir contenir le code countrycode, le nom name_country, le nom de la capitale name_capital et le nom de la plus grande ville name_biggest_city d un pays. 1. Quel est le type de chacune des colonnes de CountryCapital? Pour CountryCapital, character(3),text,text,text. Pour lister les types des colonnes d une table : SELECT column name, data type FROM information schema. columns WHERE table name= country AND table schema= world ; 2. Remplissez-là à partir des informations du schéma world. Les pays n ayant pas de villes doivent avoir les champs name_capital et name_biggest_city à NULL. CREATE TABLE e n t i d. c o u n t r y c a p i t a l AS SELECT co. countrycode, co. name country, c i. name city as name capital, e n t i d. b i g g e s t c i t y ( co. name country ) FROM world. country co LEFT OUTER JOIN world. c i t y c i ON ( co. c a p i t a l=c i. i d ) ; 3. Modifier la table CountryCapital pour que tous les noms apparaissant dedans soient mis en majuscules. On utilisera la fonction UPPER qui prend une chaîne de caractères en argument et renvoie la même chaîne en majuscule. UPDATE e n t i d. c o u n t r y c a p i t a l SET name country = upper ( name country ), name capital = upper ( name capital ) b i g g e s t c i t y = upper ( b i g g e s t c i t y ) ; 4. Supprimez tous les pays de CountryCapital qui ont une population inférieure à 5000. DELETE FROM e n t i d. c o u n t r y c a p i t a l USING world. country co cc 4
WHERE co. countrycode=cc. countrycode AND co. population country < 5000 ; 5. Créer une table continent avec les colonnes continent_id qui contient le numéro d identification d un continent donné par la table world.code_cotinent et les colonnes name_continent, surface, population, lifeexpectancy et gnp qui contient respectivement le nom, la surface et la population totale et l espérance de vie et le PNB moyen par pays du continent. CREATE TABLE e n t i d. c o n t i n e n t AS SELECT c o d e c o n t i n e n t, c o n t i n e n t as name continent, sum( s u r f a c e ), sum( p o p u l a t i o n c o u n t r y ), avg ( l i f e e x p e c t a n c y ), avg ( gnp ) FROM world. c o d e c o n t i n e n t ct NATURAL JOIN world. country co GROUP BY c o d e c o n t i n e n t, c o n t i n e n t ; NB : Faire la moyenne des espérances de vie et des gnp sans pondérer par les populations respectives est aberrant. CREATE TABLE e n t i d. c o n t i n e n t AS SELECT c o d e c o n t i n e n t, c o n t i n e n t as name continent, sum( s u r f a c e ), sum( p o p u l a t i o n c o u n t r y ), sum( p o p u l a t i o n c o u n t r y l i f e e x p e c t a n c y ) /sum ( p o p u l a t i o n c o u n t r y ), sum( p o p u l a t i o n c o u n t r y gnp ) /sum( p o p u l a t i o n c o u n t r y ) FROM world. c o d e c o n t i n e n t ct NATURAL JOIN world. country co GROUP BY c o d e c o n t i n e n t, c o n t i n e n t ; 5 DM 1. (a) Créez dans votre schéma, une table moncontinent, copie partielle de la table world.country. Votre copie contiendra les tuples correspondants aux pays du continent dont le code (donné par la table world.code_continent) est égal à 1 + (officialcode %7) où officialcode est votre numéro d inscription à Paris- Diderot (212xxxxx si vous vous êtes inscrit pour la première fois en 2012). (b) Insérer dans votre table, un tuple correspondant à un pays imaginaire. 2. Créer dans votre schéma, une vue ville_pays, de schéma (pays, ville, est_capitale, pourcentage_pop), où pays est le nom du pays, est_capitale vaut TRUE si l attribut ville est le nom de la capitale du pays désigné par l attribut pays, et FALSE sinon, et pourcentage_pop désigne le pourcentage de la population du pays résidant dans la ville. 5