Utiliser une base de données relationnelle sous R Fichier
Transcription
Utiliser une base de données relationnelle sous R Fichier
Ecole doctorale 227 Sciences de la Nature et de l’Homme Module R : APPLICATIONS Utiliser une base de données relationnelle sous R Initiation au langage SQL Raymond Baudoin Conservatoire botanique national du Bassin parisien Département EGB [email protected] 23 avril 2012 24/04/2012 Utiliser SQL pour manipuler des données sous Pour un utilisateur de R Quand on veut filtrer les données à traiter car : Elles sont trop nombreuses Qu’une partie seulement nous intéresse Elles sont éclatées dans plusieurs entités (fichiers) C’est-à-dire chaque fois qu’un read.table() n’est pas totalement satisfaisant * (*) permet cependant la restriction du nombre de lignes lues Pour un utilisateur SQL : Quand on souhaite y appliquer des fonctions de R Librairies utilisées : pour la connexion aux bases de données : RODBC, RSQLite, RMySQL, RPostgreSQL, ROracle, DBI pour accéder aux données des : fichiers txt, .csv : sqldf fichiers Excel : RODBC, xlsReadWrite, xlsx bases de données : RODBC, RSQLite, RMySQL, RPostgreSQL, ROracle, DBI pour manipuler des data frames : sqldf 24/04/2012 Fonctions de base pour lire un fichier texte Si le fichier est sous la forme d'un tableau statistique : read.table (file = fich , # Nom complet du fichier ou "clipboard" pour le presse papier (copier/coller) sep = ";" , # Séparateur des valeurs, \t pour tabulation, \n : pas de séparateur dec = "," , # Symbole décimal header = FALSE , stringsAsFactors = TRUE , # Conversion des chaines en facteur row.names = 1, # colonne utilisée comme identifiant des lignes skip = 1, nrow = 3 ) # Restriction de lecture, ici saut de la première ligne et 3 lignes lues > read.table (file = "Habitants.csv", sep=";", header=FALSE, nrow=2) V1 V2 V3 V4 V5 V6 V7 V8 V9 1 pk Nom Prénom numéro voie Code Ville Téléphone Depuis 2 1 Lecesve André 9 rue Gay Lussac 92320 CHATILLON 146542856 19/10/1920 > read.csv2 (file = "Habitants.csv", row.names=1, nrow=2) Nom Prénom numéro voie Code Ville Téléphone Depuis 1 Lecesve André 9 rue Gay Lussac 92320 CHATILLON 146542856 19/10/1920 2 Larrouy Catherine 10 rue Gay Lussac 92320 CHATILLON 140920841 01/01/1999 > read.delim2 ("clipboard", row.names=1, nrow=2) Nom Prénom numéro voie Code Ville Téléphone Depuis 1 Lecesve André 9 rue Gay Lussac 92320 CHATILLON 146542856 19/10/1920 2 Larrouy Catherine 10 rue Gay Lussac 92320 CHATILLON 140920841 01/01/1999 Si le fichier est sous une autre forme : scan (file = fich , sep=";", what = "character", skip = 1, Copier/Coller d'une feuille Excel nlines = 3) > scan (file = "Habitants.csv", sep=";", what = "character",skip=1, nlines=2) Read 18 item [1] "1" "Lecesve" "André" "9" "rue Gay Lussac" "92320" [8] "146542856" "19/10/1920" "2" "Larrouy" "Catherine" "10" [15] "92320" "CHATILLON" "140920841" "01/01/1999" "CHATILLON" "rue Gay Lussac" readLines (con = fich, n = 3) > readLines (con = "Habitants.csv", n=2) [1] "pk;Nom;Prénom;numéro;voie;Code;Ville;Téléphone;Depuis" [2] "1;Lecesve;André;9;rue Gay Lussac;92320;CHATILLON;146542856;19/10/1920 24/04/2012 Fonctions pour lire une feuille MS-Excel R ≥ 2.12.2 au format .xls (Excel 97/2000/XP/2003) ou .xlsx (Excel 2007) library (xlsx) read.xlsx2 ( read.xlsx ( file, sheetIndex=, # nom du fichier # numéro de la feuille sheetName=NULL, # ou son nom as.data.frame=TRUE, header=TRUE, colClasses=NA, # numeric, integer, logical, character, Date rowIndex=NULL, colIndex=NULL, keepFormulas=FALSE, encoding="unknown", ...) file, sheetIndex=, # nom du fichier sheetName=NULL, as.data.frame=TRUE, header=TRUE, colClasses="character", startRow=1, startColumn=1, noRows=NULL, noColumns=NULL) # ou son nom # numéro de la feuille # ou "numeric" # nombre de lignes à lire read.xlsx ("OCCSOL_1000.xlsx", sheetIndex=1, rowIndex=c(1:4,rep(0,135-4)) ) NA. BB BH BI BM BT O TR VB VG VH VM 1 0 0.0787 25.2158 30.0836 15.3149 1.1547 0.0465 6.5254 5.4042 3.2627 5.0906 7.8229 2 1 0.2431 22.2879 27.8258 22.7205 1.1578 0.0000 5.9316 5.1204 2.8737 3.8698 7.9693 3 2 0.1411 16.7779 23.4831 8.4136 0.7781 18.2162 7.0589 6.9271 2.5255 6.9970 8.6815 read.xlsx2 ("OCCSOL_1000.xlsx", sheetIndex=1, colClasses="numeric", startRow=1, noRows=3) c.0..1. BB BH BI BM BT O TR VB VG VH VM 1 0 0.0787 25.2158 30.0836 15.3149 1.1547 0.0465 6.5254 5.4042 3.2627 5.0906 7.8229 2 1 0.2431 22.2879 27.8258 22.7205 1.1578 0.0000 5.9316 5.1204 2.8737 3.8698 7.9693 read.xlsx ("Habitants.xls", sheetIndex=1, rowIndex=c(1:3,rep(0,14-3)), encoding="UTF-8", stringsAsFactors=FALSE) Nom Prénom numéro Adresse Code Ville Téléphone Depuis 1 Lecesve André 9 rue Gay Lussac 92320 CHATILLON 146542856 1920-10-19 2 Larrouy Catherine 10 rue Gay Lussac 92320 CHATILLON 140920841 1999-01-01 24/04/2012 Fonctions pour lire une feuille MS-Excel au format .xls library (xlsReadWrite) read.xls( file, colNames = TRUE, sheet = 1, colClasses = NA, # numeric, integer, logical, character, isodate, isotime, isodatetime… stringsAsFactors = TRUE… ) fich <- file.choose() # chemin complet # [1] "C:\\Mes documents sauvegardés\\Enseignement\\Ecole doctorale mnhn\\Module R compl\\Habitants.xls" Encoding (fich) fich <- iconv (fich , from = Encoding (fich), to = "latin1") # "UTF-8" # changement de code page read.xls (file = fich, sheet = 1, stringsAsFactors = FALSE) 1 2 3 Nom Lecesve Larrouy Larrouy Prénom numéro Adresse Code Ville Téléphone Depuis André 9 rue Gay Lussac 92320 CHATILLON 146542856 7598 Catherine 10 rue Gay Lussac 92320 CHATILLON 140920841 36161 Eric 10 rue Gay Lussac 92320 CHATILLON 140920841 36161 read.xls (file=fich, sheet=1, stringsAsFactors=FALSE, dateTime="isodatetime") 1 2 3 Nom Lecesve Larrouy Larrouy Prénom numéro Adresse Code Ville Téléphone Depuis André 9 rue Gay Lussac 92320 CHATILLON 146542856 1920-10-19 Catherine 10 rue Gay Lussac 92320 CHATILLON 140920841 1999-01-01 Eric 10 rue Gay Lussac 92320 CHATILLON 140920841 1999-01-01 Pour enregistrer un data.frame au format MS-Excel : write.xls(datal, file="localisation.xls", rowNames = TRUE) 24/04/2012 SGBD : Système de gestion de base de données Ou DBMS (Database management system) Un ensemble de services pour : permettre l'accès aux données de façon simple autoriser un accès aux informations à de multiples utilisateurs manipuler les données présentes dans la base (insertion, suppression, modification) Se décompose en trois sous-systèmes : un système de gestion de fichiers pour le stockage des informations sur le support physique un système pour gérer l'ordonnancement des informations une interface avec l'utilisateur 24/04/2012 Elément de base : la table • Les données sont réparties en tables ou entités • Une table est composée de lignes • Une ligne est un ensemble fixe de champs (attributs) Chaque champ a : un nom • un type id Nom Prénom 1 Lecesve André 2 Larrouy 3 Exemple : la table Personnes numéro id_localisation 9 2 146542856 19/10/1920 Catherine 10 2 140920841 01/01/1999 Larrouy Eric 10 2 140920841 01/01/1999 6 Meyer Michel 15 3 8 Auquier Anne 21 3 157750048 05/09/2005 9 Auquier Anne 21 3 636699001 05/09/2005 10 Auquier Bernard 21 3 146428564 05/09/2005 INTEGER CHARACTER INTEGER Propriétés d’une table : • pas de nom de colonne dupliqué • ordre des lignes sans signification • ordre des colonnes (champs) sans signification • chaque champ permet la sélection de lignes Téléphone Depuis 05/06/1960 DECIMAL DATE Avec ces propriétés, une table : un fichier une feuille xls 24/04/2012 Les types de champs Type SQL octet Valeurs limites 1/2 Les types normalisés SQL 2 MS Access Nature Remarque numériques SMALLINT 2 32 768 INTEGER (ou INT) 4 2 147 483 647 NUMERIC (ou DECIMAL ou DEC) 12 (10^28) -1 REAL 4 3.402823E38 FLOAT 8 1,7976931E308 DOUBLE PRECISION 8 Entier entier court Entier Long entier long nombre décimal représentation exacte (précision, échelle), 28 décimales Réel simple réel à virgule flottante représentation binaire, 7 décimales Réel double réel à virgule flottante représentation binaire, précision obligatoire, 15 décimales réel à virgule flottante représentation binaire chaîne de bit longueur fixe caractères (ou CHARACTER) caractères (ou CHARACTER VARYING) Décimal BIT alphanumériques CHAR 255 VARCHAR 32767 Texte (ou NATIONAL CHARACTER) NCHAR temporels TIMESTAMP 8 Date/Heure combiné date temps DATE date du calendrier grégorien TIME temps sur 24 heures 24/04/2012 Les types de champs 2/2 Les types non normalisés SQL 2 Type SQL octet Valeurs limites MS Access 65 536 Mémo () Nature Remarque BLOBS caractères longueur indéterminé IMAGE image stockage dans un format déterminé OLE objet OLE Windows TEXT autres types BOOLEAN ou LOGICAL Oui/Non MONEY Monétaire BYTES 1 octet AUTOINC 4 NuméroAuto NUMERIC précision de deux chiffres. ou BINARY entier à incrément automatique 24/04/2012 SGBDR : Le modèle relationnel Entités Objectif du modèle : Pas d’information redondante Attributs Relation Cardinalité : dénombre le nombre d'éléments de l'entité départ en relation avec un élément de l'entité arrivée. La clef primaire d'une table est un attribut ou un groupe d'attributs de cette table dont la valeur permet d'identifier de manière unique une ligne de la table. Permet la création de liaisons fixes entre les tables en mettant en relation un ou plusieurs champs. Relations possibles : 1/1, 1/n, n/1, n/m Une relation n/m nécessite une table de jointure 24/04/2012 SGBDR : Le modèle relationnel • 1 nom à n téléphones • 1 téléphone est partagé par m nom relation n / m table de jointure L'attribut id de l'entité xxx = clé primaire de la table xxx permet la relation avec l'entité yyy via l'attribut id_xxx = clé étrangère de la table yyy 24/04/2012 SQLite : SGBDR portable utilisable sous • • • • • moteur de base de données relationnelles accessible par le langage SQL. implémente en grande partie le standard SQL-92 la base de données (déclarations, tables, index et données) stockée dans un fichier utilisation sans restriction dans des projets aussi bien open source que propriétaires multi-plateforme Une « interface » utilisateur : SQLite Database Browser http://www.sqlite.org/ SQLite est le moteur de base de données le plus distribué au monde, grâce à son utilisation dans de nombreux logiciels grand public comme Firefox, Skype, Google Gears, dans certains produits d'Apple, d'Adobe et de McAfee et dans les librairies standards de nombreux langages comme PHP ou Python. De par son extrême légèreté (moins de 300 ko), elle est également très populaire sur les systèmes embarqués, notamment sur la plupart des smartphones modernes. http://sqlitebrowser.sourceforge.net/ La librairie sqldf permet à d'utiliser SQLite 24/04/2012 Pourquoi se connecter au SGBD ? Sans connexion copier coller fichier .txt .csv Serveur de données SGBD (DBMS) Excel fichier texte read.table() read.csv2() sélection export A refaire si les données sont modifiées ou si mauvaise sélection Introduction d’un fichier intermédiaire l’intégrité des données n’est plus respectée Avec connexion Serveur de données SGBD (DBMS) Interface de connexion Excel fichier texte odbcDriverConnect() sqlFetch() sqlQuery() Intégrité des données respectée Sélection des données dans R 24/04/2012 Accès à l'application gérant les données Interface de connexion Application Serveur de données SGBD (DBMS) DBI Excel fichier texte database interface ODBC Open DataBase Connectivity ODBC : interface spécialisée L'application doit avoir un pilote ODBC. Exemple : pilote ODBC SQLite http://www.ch-werner.de/sqliteodbc/sqliteodbc.exe L’interface doit : Identifier l'application Etablir la connexion Renvoyer les données rôle des objets de DBI Driver DBI Connexion Dans ce cas la connexion se fait directement sur le pilote ODBC de l'application DBI Résultats 24/04/2012 Des packages R spécifiques* Interface de connexion R ≥ 2.9 Application Serveur de données RMySQL Package source: RMySQL_0.7-4.tar.gz MacOS X binary: RMySQL_0.7-4.tgz Windows binary: RMySQL_0.7-4.zip MySQL RPostgreSQL Package source: RPostgreSQL_0.1-6.tar.gz MacOS X binary: Non disponible Windows binary: RPostgreSQL_0.1-6.zip PostgreSQL ROracle Package source: ROracle_0.5-9.tar.gz MacOS X binary: Non disponible Windows binary: Non disponible Oracle RSQLite Package source: RSQLite_0.8-2.tar.gz MacOS X binary: RSQLite_0.8-2.tgz Windows binary: RSQLite_0.8-2.zip SQLite RODBC Package source: RODBC_1.3-1.tar.gz MacOS X binary: RODBC_1.3-1.tgz Windows binary: RODBC_1.3-1.zip Bases de données ayant un pilote ODBC : Access, Excel, SQLite... * Contient à la fois le driver et l'interface (DBI) 24/04/2012 ODBC = Open DataBase Connectivity (format défini par Microsoft) Couche logiciel qui permet la connexion d’une application windows à une source de données La source de données est identifiée par son DSN = Data Source Name Machine utilisateur Serveur de données distant Microsoft, UNIX, Linux Applications windows ODBC DSN Client Microsoft SGBD Driver ODBC correspondant à l'application source Client Oracle Oracle 24/04/2012 Connexion à une base de données via ODBC channel <- odbcDriverConnect () La base est dans un répertoire accessible La base est sur un serveur distant Configurer un lien ODBC sous Windows • Démarrer • Panneau de configuration • Outils d’administration • Sources de données (ODBC) Contrôle de l’accès si activé Configuration du DSN L’accès à la base est décrit dans le dsn associé dans C:\Program Files\Fichiers communs\ODBC\Data Sources Permet d’identifier la source Nom de la base à connecter 24/04/2012 Connexion : la démarche Connexion via DBI via ODBC exemple : SGBD sqlite 1. charger la librairie library (RSQLite) 2. charger le pilote drv <- dbDriver ("SQLite") 3. ouvrir une connexion sur les données con <- dbConnect (drv, dbname=*...) * nom de la base uniquement 4. voir la structure des données (non obligatoire) dbListTables (con) dbListFields (con, "sqtable") library (RODBC) channel <- odbcDriverConnect() ou channel <- odbcConnectExcel(…) channel <- odbcConnectAccess(…) sqlTables (channel,…) sqlColumns (channel, sqtable,…) dbGetRowCount (res); dbColumnInfo (res) 5. charger les données avec tous les champs dbReadTable (con, sqtable) sqlFetch (channel, sqtable,…) 6. charger les données avec un SELECT (sql) res <- dbSendQuery (con, sql) sqlQuery (channel, sql,…) fetch (res, n = -1) dbGetQuery (channel, sql,…) 7. fermer la connexion : OBLIGATOIRE pour libérer l’accès dbDisconnect (con) close(channel) ou odbcClose(channel) odbcCloseAll() 24/04/2012 8. libérer le pilote : dbUnloadDriver (drv) Exemples de connexion à une base sqlite : "SeminR.db" Via DBI library (RSQLite) # Se mettre dans le répertoire de la base setwd(choose.dir()) db <- "SeminR.db" drv <- dbDriver("SQLite") con <- dbConnect(drv, dbname=db) drv <SQLiteDriver:(2192)> con <SQLiteConnection:(2192,0)> dbGetInfo(drv)$num_con [1] 1 # nombre de connexion dbGetInfo(con) $dbname [1] "SeminR.db" $serverVersion [1] "3.6.21" $rsId integer(0) $loadableExtensions [1] "off" $flags [1] 6 $vfs [1] "" à une base Access Via ODBC library (RODBC) library (RODBC) (conn <- file.choose()) [1] "C:\\...\\Séminaire R\\RODBC.mdb" c_sqlite <- odbcDriverConnect() c_sqlite RODBC Connection 10 Details: case=nochange DSN=SemirR3 Database=C:\Mes documents sauvegardés\Enseignement\Séminaire R\Nouveau 2010\SeminR.db StepAPI=0 SyncPragma=NORMAL NoTXN=0 Timeout= ShortNames=0 LongNames=1 NoCreat=0 NoWCHAR=0 JournalMode= LoadExt= channel <- odbcConnectAccess (conn) channel RODBC Connection 11 Details: case=nochange DBQ=C:\Mes documents sauvegardés\Enseignement\Séminaire R\RODBC.mdb Driver={Microsoft Access Driver (*.mdb)} DriverId=25 FIL=MS Access MaxBufferSize=2048 PageTimeout=5 UID=admin dbDisconnect (con) [1] TRUE con <Expired SQLiteConnection: DBI CON (2192, 0)> 24/04/2012 Accès aux structures DBI dbListTables(con) [1] "Habitants" "localisation" "personnes" sqlTables (c_sqlite) TABLE_CAT TABLE_SCHEM TABLE_NAME TABLE_TYPE REMARKS 1 <NA> <NA> Habitants TABLE <NA> 2 <NA> <NA> localisation TABLE <NA> 3 <NA> <NA> personnes TABLE <NA> sqlTables (channel) Tables ODBC 1 2 3 4 5 6 7 8 9 TABLE_CAT TABLE_SCHEM TABLE_NAME TABLE_TYPE REMARKS C:\\...\\Séminaire R\\RODBC <NA> MSysAccessObjects SYSTEM TABLE <NA> C:\\...\\Séminaire R\\RODBC <NA> MSysAccessXML SYSTEM TABLE <NA> C:\\...\\Séminaire R\\RODBC <NA> MSysACEs SYSTEM TABLE <NA> C:\\...\\Séminaire R\\RODBC <NA> MSysObjects SYSTEM TABLE <NA> C:\\...\\Séminaire R\\RODBC <NA> MSysQueries SYSTEM TABLE <NA> C:\\...\\Séminaire R\\RODBC <NA> MSysRelationships SYSTEM TABLE <NA> C:\\...\\Séminaire R\\RODBC <NA> Habitants TABLE <NA> C:\\...\\Séminaire R\\RODBC <NA> Localisation TABLE <NA> C:\\...\\Séminaire R\\RODBC <NA> Personnes TABLE <NA> sqtable = "localisation" dbExistsTable (con, sqtable) DBI [1] TRUE dbListFields( con, sqtable) [1] "id" "Adresse" "Code" "Ville" sqlColumns (c_sqlite, sqtable)[,3:6] Champs ODBC 1 2 3 4 TABLE_NAME COLUMN_NAME DATA_TYPE TYPE_NAME localisation id 4 INTEGER localisation Adresse -9 VARCHAR localisation Code 8 NUMERIC localisation Ville -10 TEXT sqlColumns (channel, sqtable)[,3:6] 1 2 3 4 TABLE_NAME COLUMN_NAME DATA_TYPE TYPE_NAME localisation id 4 COUNTER localisation Adresse 12 VARCHAR localisation Code 4 INTEGER localisation Ville 12 VARCHAR 24/04/2012 Travailler avec les tables via ODBC Créer une table En enregistrant un data.frame : sqlSave () sqlSave(channel, datal[1:2,], rownames ="pk", addPK =TRUE) Par défaut : tablename = nom du data.frame Création d’une clef primaire nommée pk sqlQuery(channel,"SELECT * FROM datal") pk id Adresse Code Ville 1 1 1 avenue Verdun 92170 VANVES 2 2 2 rue Gay Lussac 92320 CHATILLON En copiant la structure d'une table existante : sqlCopyTable () Nom de la table à copier (source) sqlCopyTable(channel, srctable, desttable, destchannel = channel) Nom de la nouvelle table et sa localisation En copiant le résultat d'une requête : sqlCopy () "SELECT ... FROM ... ;" sqlCopy(channel, query, desttable, destchannel = channel) Nom de la nouvelle table et sa localisation 24/04/2012 Travailler avec les tables via ODBC Ajouter des lignes à une table : sqlSave () # ajouter la 3ème ligne du data.frame datal # à la table de même nom sqlQuery(channel,"SELECT * FROM datal") pk id Adresse Code Ville 1 1 1 avenue Verdun 92170 VANVES 2 2 2 rue Gay Lussac 92320 CHATILLON 3 3 3 rue Roissis 92140 CLAMART sqlSave (channel, datal[3,], rownames = "pk", addPK = TRUE, append = TRUE) Modifier des lignes d’une table : sqlUpdate () # modification de la 3ème ligne de datal datal[3,3:4] = datal[1,3:4] datal <- cbind(rownames(datal),datal) colnames(datal)[1] <- "pk" sqlQuery(channel,"SELECT * FROM datal") pk id Adresse Code Ville 1 1 1 avenue Verdun 92170 VANVES 2 2 2 rue Gay Lussac 92320 CHATILLON 3 3 3 rue Roissis 92170 VANVES sqlUpdate (channel, datal[3,], tablename = "datal", index = "pk") 24/04/2012 Travailler avec les tables via ODBC Supprimer toutes les lignes d’une table : sqlClear () sqlClear (channel, "datal") sqlQuery(channel,"SELECT count(*) FROM datal") Expr1000 1 0 Mais la structure de la table existe toujours sqlSave(channel,datal,rownames = FALSE, append = TRUE) sqlQuery(channel,"SELECT count(*) FROM datal") Expr1000 1 3 Supprimer une table sqlDrop () sqlDrop (channel,"datal") 24/04/2012 Pas de sélection de colonnes Accès aux données (dDBI <- dbReadTable(con, sqtable)) DBI id Adresse 1 1 avenue Verdun 2 2 rue Gay Lussac 3 3 rue Roissis Code Ville 92170 VANVES 92320 CHATILLON 92140 CLAMART str(dDBI) 'data.frame': 3 obs. of 4 variables: $ id : int 1 2 3 $ Adresse: chr "avenue Verdun" "rue Gay Lussac" "rue Roissis" $ Code : int 92170 92320 92140 $ Ville : chr "VANVES" "CHATILLON" "CLAMART" (dODBC <- sqlFetch (c_sqlite, sqtable)) localisation.id localisation.Adresse localisation.Code localisation.Ville 1 1 avenue Verdun 92170 VANVES 2 2 rue Gay Lussac 92320 CHATILLON 3 3 rue Roissis 92140 CLAMART str(dODBC) ODBC 'data.frame': 3 obs. of 4 variables: $ localisation.id : int 1 2 3 $ localisation.Adresse: Factor w/ 3 levels "avenue Verdun",..: 1 2 3 $ localisation.Code : num 92170 92320 92140 $ localisation.Ville : Factor w/ 3 levels "CHATILLON","CLAMART",..: 3 1 2 Pour avoir des caractères, mettre le paramètre stringsAsFactors = FALSE 24/04/2012 Utilisation de sqlFetch() sqlFetchMore() Commande RODBC Charger les données ligne(s) à ligne(s) sqlFetch (channel,"personnes", max=3) Nom Prénom numéro Adresse 1 Lecesve André 9 rue Gay Lussac 2 Larrouy Catherine 10 rue Gay Lussac 3 Larrouy Eric 10 rue Gay Lussac Code Ville Téléphone Depuis 92320 CHATILLON 146542856 1920-10-19 92320 CHATILLON 140920841 1999-01-01 92320 CHATILLON 140920841 1999-01-01 sqlFetchMore (channel, max=1) Nom Prénom numéro Adresse Code Ville Téléphone Depuis 1 Malher Goerges 13 rue Gay Lussac 92320 CHATILLON 146576986 1960-06-05 Gestion d’un curseur lignes 1 à max 4 curseur + max sqlFetchMore (channel) 1 2 3 4 5 6 7 8 9 Nom Prénom numéro Adresse Lipinski Ludovic 15 rue Gay Lussac Meyer Michel 15 rue Roissis Foucher Georges 17 rue Roissis Auquier Anne 21 rue Roissis Auquier Anne 21 rue Roissis Auquier Bernard 21 rue Roissis Mahier Ludovic 3 avenue Verdun Berrue Christiane 4 avenue Verdun Berrue Christiane 4 avenue Verdun Code Ville Téléphone Depuis 92320 CHATILLON 147352329 1952-09-23 92140 CLAMART NA 1960-06-05 92140 CLAMART 146449501 2000-02-03 92140 CLAMART 157750048 2005-09-05 92140 CLAMART 636699001 2005-09-05 92140 CLAMART 146428564 2005-09-05 92170 VANVES 147361266 1983-05-07 92170 VANVES 146381434 1985-10-21 92170 VANVES 954912355 1985-10-21 5 à 13 sqlFetchMore (channel, max=1) [1] -1 code de fin 24/04/2012 Connexion ODBC à un classeur Excel Par sélection dans un menu channel <- odbcConnectExcel() Par son nom ( conn <- file.choose() ) [1] "C:\\Mes documents sauvegardés\\Enseignement \\CoursStat\\Séminaire R\\Habitants.xls" channel <- odbcConnectExcel(conn) channel RODB Connection 3 Details: case=nochange DBQ=C:\Mes documents sauvegardés\Enseignement\Séminaire R\Habitants.xls DefaultDir=C:\Mes documents sauvegardés\Enseignement\Séminaire R Driver={Microsoft Excel Driver (*.xls)} DriverId=790 MaxBufferSize=2048 PageTimeout=5 Ouvrir la connexion avec l’option d’écriture (par défaut : readOnly = TRUE) channel <- odbcConnectExcel (conn, readOnly = FALSE) 24/04/2012 Commandes RODBC Accès aux données Excel Commandes identiques à l'accès à un SGBDR sauf sqlQuery() Voir la structure des données : description du classeur sqlTables(channel) TABLE_CAT TABLE_SCHEM TABLE_NAME TABLE_TYPE REMARKS 1 C:\\Mes documents sauvegardés\\Enseignement\\Séminaire R\\Habitants <NA> Feuil1$ SYSTEM TABLE 2 C:\\Mes documents sauvegardés\\Enseignement\\Séminaire R\\Habitants <NA> Feuil2$ SYSTEM TABLE 3 C:\\Mes documents sauvegardés\\Enseignement\\Séminaire R\\Habitants <NA> Feuil3$ SYSTEM TABLE <NA> <NA> <NA> Charger les données : sqlFetch() data <- sqlFetch (channel, "Feuil1") nom de la connexion nom de la « table » obligatoire Ecriture des données dans une nouvelle feuille sqlSave(channel, data1, tablename = "New", rownames = FALSE) data.frame des données nom de la feuille TRUE par défaut Nouveau nom de feuille obligatoire Ajouter des données dans une feuille sqlSave(channel,data1,tablename = "New", rownames = FALSE, append = TRUE) Obligatoire : fermer la connexion pour accéder au fichier par Excel close(channel) Pas d’écrire possible dans une feuille vide existante. Possible que si la feuille à des données 24/04/2012 SQL (Structured Query Language) Utilisation du language SQL pour sélectionner : des colonnes des lignes d'une ou plusieurs tables par l'utilisation d'une requête SQL 24/04/2012 SQL (Structured Query Language) Langage normalisé pour décrire, manipuler, contrôler l'accès et interroger les bases de données relationnelles Caractéristiques Inventé en 1970 Déclaratif c'est-à-dire indépendant du contexte d'exécution Régi par une norme ANSI/ISO Première normalisation ISO en 1987 SQL 2 correspond à la norme SQL/92 SQL 3 en 1999, actuellement SQL 2003 Portable sur différentes plates-formes aussi bien matérielles que logicielles. Une commande SQL écrite dans un environnement Windows sous MS-ACCESS est utilisable directement dans un environnement ORACLE sous Unix. 24/04/2012 SQL (Structured Query Language) Langage de requêtes structuré regroupant : un langage de contrôle des accès (DCL, Data Control Language) un langage de définition de données (DDL Data Definition Language) Pour créer, modifier ou supprimer des tables dans la base un langage de manipulation de données (DML, Data Manipulation Language) Pour sélectionner, insérer, modifier ou supprimer des données dans une table 24/04/2012 Les commandes SQL DCL : Contrôle des données GRANT Attribution de droits d'accès REVOKE Suppression de droits d'accès COMMIT Prise en compte des mises à jour ROLLBACK Suppression des mises à jour DDL : Description des données CREATE Création de tables ALTER Modification de tables DROP Suppression de tables DML : Manipulation des données SELECT Interrogation des données INSERT UPDATE DELETE Insertion de lignes dans une table Mise à jour de lignes dans une table Suppression de lignes dans une table 24/04/2012 Syntaxe de la commande SELECT SELECT [ALL | DISTINCT] { * | col | expr [AS alias], ... } FROM table [alias], ... [ WHERE { conditions de recherche | sous conditions} ] [ GROUP BY col, ...] [HAVING conditions de recherche ] [ ORDER BY { col | num } {ASC | DESC}, ...] ; Légende : { } : Une des valeurs séparées par '|' obligatoire. [ ] : Valeur optionnelle. ... : Répétition. __ : Valeur par défaut. SELECT FROM WHERE Précise les colonnes qui vont apparaître dans la réponse Précise la (ou les) table intervenant dans l'interrogation Précise les conditions à appliquer sur les lignes avec : - Des opérateurs de comparaison : =, >, <, >=, <=,<> - Des opérateurs logiques : AND, OR, NOT - Des prédicats : IN, LIKE, NULL, ALL, ANY... GROUP BY Précise la (ou les) colonne de regroupement HAVING Précise la (ou les) conditions associées à un regroupement ORDER BY Précise l'ordre dans lequel vont apparaître les lignes de la réponse : - ASC : ordre ascendant (par défaut) - DESC : ordre descendant 24/04/2012 Accès aux données via SQL La requête : sql <- "SELECT * FROM localisation ;" dbGetQuery(con, sql) id Adresse 1 1 avenue Verdun 2 2 rue Gay Lussac 3 3 rue Roissis Code Ville 92170 VANVES 92320 CHATILLON 92140 CLAMART Première utilisation res <- dbSendQuery(con, sql) # Prépare la requête fetch (res, n = 2) # Affiche n lignes (curseur), si n = -1 → jusqu’à la fin 1 2 id Adresse Code Ville 1 avenue Verdun 92170 VANVES 2 rue Gay Lussac 92320 CHATILLON dbGetRowCount(res) DBI Deuxième utilisation # nb lignes lues [1] 2 dbHasCompleted(res) # test la fin de l’affichage [1] FALSE fetch(res, n = -1) 3 id Adresse Code Ville 3 rue Roissis 92140 CLAMART dbHasCompleted(res) [1] TRUE Autres fonctions : dbClearResult (res) # libère le lien à la table. A faire pour un nouveau dbSendQuery() si dbHasCompleted(res)→FALSE dbColumnInfo (res) # à sqlColumns() dbGetStatement (res) # affiche le SELECT sqlQuery(c_sqlite, sql) ODBC 1 2 3 localisation.id localisation.Adresse localisation.Code localisation.Ville 1 avenue Verdun 92170 VANVES 2 rue Gay Lussac 92320 CHATILLON 3 rue Roissis 92140 CLAMART 24/04/2012 library (sqldf) pour l'utilisation d'une base de données sqlite sqldf () permet l'usage des requêtes SQL sur : les tables d'une base SQLite des data frames des fichiers textes Utilise les librairies : • DBI (data base interface) • RSQLite : pilote (driver) R pour l’accès à une base SQLite 24/04/2012 Connexion à une base sqlite via sqldf () Ouverture d'une connexion à la base sqlite "nom_de_la_base" * * exclusivement le nom de la base et non le chemin complet sqldf (dbname = "nom_de_la_base") Si "nom_de_la_base" non trouvé : création d'une base vide à ce nom Si dbname non précisé : ouverture d'une base virtuelle ( sqldf () ) <SQLiteConnection:(1036,0)> Fermeture de la connexion au 2ème appel sqldf () NULL Utilisation des commandes DBI : dbGetInfo(SQLite())$num_con # nombre de connexions ouvertes con <- sqldf (dbname = "nom_de_la_base") # récupération de l’identifiant de la connexion dbListTables(con) # liste les tables de la base "SQLite" connectée (*) Exemple d’un script de sélection de la base à connecter setwd(dirname(dbase <- file.choose())) # change le répertoire dbase = iconv(dbase,Encoding(dbase),"latin1") # conversion code caractère dbase <- substring(dbase,max(unlist(gregexpr("\\",dbase,fixed=TRUE)))-1) sqldf(dbname = dbase) # connexion 24/04/2012 Utiliser SQL pour manipuler des données dans library (sqldf) sqldf ("Requête SQL", dbname = ..., connection = ... ) SELECT nom* d'une base SQLite par défaut : ouvre une base virtuelle en mémoire OU * uniquement le nom de la base nom d'une connexion sur une base SQLite ouverte par : - dbConnect () - sqldf (dbname = ) par défaut • sur des tables d'une base SQLite (ou MySQL) • sur des fichiers textes • sur des data.frames Remarque sur l'ouverture / fermeture de la connexion ( sqldf() ) # ouverture d’une connexion sur une base virtuelle <SQLiteConnection:(1036,0)> ( sqldf() ) # fermeture de la connexion au 2ème appel NULL 24/04/2012 SELECT SQL via sqldf S’assurer qu’une connexion est bien ouverte 1 - Utilisation avec une base sqlite sqldf ("SELECT * FROM ma_table ;", method = "raw" ) Requête SQL "raw" Données brutes "auto" Types ajustés au "mieux" 2 - Utilisation avec un data.frame Exemple : iris sqldf ("SELECT * FROM iris ;", method = "raw", row.names = FALSE) Requête SQL "raw" Données brutes "auto" Types ajustés TRUE : ajoute une colonne row_names à la table si method= "raw" et SELECT * : ajoute une colonne row_names au data.frame Attention – Dans les cas 2, 3 et 4 si la connexion est sur une base nommée, il y aura copie de la (des) table(s) du FROM. Risque de conflit ! si la connexion ne pointe aucune base nommée, c’est la base virtuelle qui est utilisée. 24/04/2012 SELECT SQL via sqldf sur un fichier texte 3 – Avec la syntaxe sqldf fich <- file(file.choose()) # ouvre une connexion sur un fichier texte au choix attr(fich , "file.format") <- list(sep = "\t" , header = TRUE) # affectation des attributs Séparateur des champs Si nom des colonnes en 1ère ligne sqldf ("SELECT * FROM fich;", method = "auto") Requête SQL • Si pas de nom de colonne : • Si header = TRUE : si length(colnames) = ncol : si length(colnames) = ncol -1 si method= "raw" et SELECT * nomme des colonnes de V1 à Vncol nomme les colonnes avec les noms ajoute une colonne row_names à la table ajoute une colonne row_names au data.frame 4 – Avec un read.csv filtré par SELECT SQL read.csv2.sql (file.choose(), sql = "select * from file” ) «file» mot clé obligatoire Remarque : dbRemoveTable(con, "ma_table") # supprime la table "ma_table" de la base connectée 24/04/2012 sqldf () pour manipuler des données dans 1 - Utilisation avec une base SQLite requête SQL pers <- sqldf ("SELECT Nom, prenom, id_localisation FROM Personnes ;", dbname = "SeminR.db") # nom de la base condb <- dbConnect (drv = "SQLite", dbname = "SeminR.db") loca <- sqldf ("SELECT * FROM localisation ;", connection = condb) # connexion 2 - Utilisation avec des data.frames NV sql <- "SELECT Nom, Ville FROM loca , pers # data.frame WHERE loca.id = pers.id_localisation # jointure AND Nom LIKE 'L%' ;" # troncature à droite NV <- sqldf (sql) # requête exécuté dans la base virtuelle 1 2 3 4 Nom Lecesve Larrouy Larrouy Lipinski Ville CHATILLON CHATILLON CHATILLON CHATILLON 3 - Utilisation avec des fichiers textes Loc <- file ("Localisation.txt") # connexion au fichier texte attr (Loc ,"file.format") = list (sep = "\t", header=TRUE) sql1 ="SELECT DISTINCT Nom, code, NV.Ville FROM NV, Loc WHERE Loc.Ville = NV.Ville ;" # jointure sqldf (sql1) data.frame fichier texte Nom Code Ville 1 Larrouy 92320 CHATILLON 2 Lecesve 92320 CHATILLON 3 Lipinski 92320 CHATILLON 24/04/2012 sqlQuery vs sqldf Commandes RODBC Données SGBD Access Requêtes SQL Connexions channel <- odbcDriverConnect (maBase) channel <- odbcConnectAccess (maBase) sqlQuery (channel, SQL) channel <- odbcConnectAccess (paste(getwd(),"RODBC.MDB",sep="/")) Excel channel <- odbcConnectExcel (monClasseur) sqlFetch (channel, "maFeuil") mon.data.frame Commandes sqldf fichier .txt .csv channel_file <- file (monFichier) sqldf (SQL) Habitants <- file( paste(getwd(),"Habitants.txt",sep="/") ) attr(Habitants ,"file.format") = list(sep = "\t",header=TRUE) Personnes <- file( paste(getwd(),"Personnes.txt",sep="/") ) attr(Personnes ,"file.format") = list(sep = "\t",header=TRUE) Localisation <- file( paste(getwd(),"Localisation.txt",sep="/") ) attr(Localisation ,"file.format") = list(sep = "\t",header=TRUE) Comm2 <- file( paste(getwd(),"Comm2.txt",sep="/") ) attr(Comm2 ,"file.format") = list(sep = "\t",header=TRUE) 24/04/2012 Syntaxe de la commande SELECT SELECT [ALL | DISTINCT] { * | col | expr [AS alias], ... } FROM table [alias], ... [ WHERE { conditions de recherche | sous conditions} ] [ GROUP BY col, ...] [HAVING conditions de recherche ] [ ORDER BY { col | num } {ASC | DESC}, ...] ; Légende : { } : Une des valeurs séparées par '|' obligatoire. [ ] : Valeur optionnelle. ... : Répétition. __ : Valeur par défaut. SELECT FROM WHERE Précise les colonnes qui vont apparaître dans la réponse Précise la (ou les) table intervenant dans l'interrogation Précise les conditions à appliquer sur les lignes avec : - Des opérateurs de comparaison : =, >, <, >=, <=,<> - Des opérateurs logiques : AND, OR, NOT - Des prédicats : IN, LIKE, NULL, ALL, ANY... GROUP BY Précise la (ou les) colonne de regroupement HAVING Précise la (ou les) conditions associées à un regroupement ORDER BY Précise l'ordre dans lequel vont apparaître les lignes de la réponse : - ASC : ordre ascendant (par défaut) - DESC : ordre descendant 24/04/2012 Alias renommer une colonne ou une table (cf auto jointure) sql <- "SELECT Adresse AS Voie, Code AS [Code postal], Ville AS Commune FROM Localisation;" Voie Code postal Commune 1 avenue Verdun 92170 VANVES 2 rue Gay Lussac 92320 CHATILLON 3 rue Roissis 92140 CLAMART sql <- "SELECT Ville, ' - ' AS Sep, Code AS CP FROM Localisation;" Ville Sep CP 1 VANVES - 92170 2 CHATILLON - 92320 3 CLAMART - 92140 Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 ORDER BY Trier la sélection croissant ou alphabétique : ASC (par défaut) sql <- "SELECT * FROM Localisation ORDER BY Code;" id Adresse Code Ville 1 3 rue Roissis 92140 CLAMART 2 1 avenue Verdun 92170 VANVES 3 2 rue Gay Lussac 92320 CHATILLON sql <- "SELECT * FROM Localisation ORDER BY Ville;" id Adresse Code Ville 1 2 rue Gay Lussac 92320 CHATILLON 2 3 rue Roissis 92140 CLAMART 3 1 avenue Verdun 92170 VANVES décroissant DESC sql <- "SELECT * FROM Localisation ORDER BY Code desc;" id Adresse Code Ville 1 2 rue Gay Lussac 92320 CHATILLON Exécution de la requête SQL : 2 1 avenue Verdun 92170 VANVES sqldf (sql) 3 3 rue Roissis 92140 CLAMART sqlQuery (channel, sql) 24/04/2012 DISTINCT Supprimer les lignes identiques sql <- "SELECT DISTINCT Nom FROM Personnes;" 1 2 3 4 5 6 7 8 9 Nom Auquier Berrue Foucher Larrouy Lecesve Lipinski Mahier Malher Meyer Remarque : DISTINCT trie aussi Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) sql <- "SELECT Nom, Prénom FROM Personnes ORDER BY Nom, Prénom;" Nom Prénom 1 Auquier Anne 2 Auquier Anne 3 Auquier Bernard 4 Berrue Christiane 5 Berrue Christiane 6 Foucher Georges 7 Larrouy Catherine 8 Larrouy Eric 9 Lecesve André 10 Lipinski Ludovic 11 Mahier Ludovic 12 Malher Goerges 13 Meyer Michel 24/04/2012 COUNT () Compter des enregistrements # nombre d'enregistements de la table sql <- "SELECT count(*) FROM Personnes;" count(*) 1 13 # nombre d'enregistements pour un champ sql <- "SELECT count(Nom) FROM Personnes;" count(*) 1 13 sql <- "SELECT count(Distinct Nom) FROM Personnes;" count(Distinct Nom) 1 9 sql <- "SELECT count(Téléphone) FROM Personnes;" count(Téléphone) 1 12 Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 WHERE Introduire des conditions de recherche sql <- "SELECT * FROM Localisation WHERE ville = 'VANVES' ;" id Adresse Code Ville 1 1 avenue Verdun 92170 VANVES sql <- "SELECT * FROM Localisation WHERE Code < 92200 ;" id Adresse Code Ville 1 1 avenue Verdun 92170 VANVES 2 3 rue Roissis 92140 CLAMART Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 LIKE Prédicats : LIKE, BETWEEN, IN, ISNULL rechercher à l'intérieur d'une chaîne de caractères % symbole de troncature _ remplace 1 caractère sql <- "SELECT * FROM Localisation WHERE Ville LIKE 'C%' ;" id Adresse Code Ville 1 2 rue Gay Lussac 92320 CHATILLON 2 3 rue Roissis 92140 CLAMART sql <- "SELECT * FROM Localisation WHERE Ville LIKE '%N%' ;" id Adresse Code Ville 1 1 avenue Verdun 92170 VANVES 2 2 rue Gay Lussac 92320 CHATILLON sql <- "SELECT * FROM Localisation WHERE Ville LIKE '_A%' ;" id Adresse Code Ville 1 1 avenue Verdun 92170 VANVES Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 IN Prédicats : LIKE, BETWEEN, IN, ISNULL rechercher dans une liste de valeurs Exemples sql <- "SELECT * FROM Localisation WHERE Code IN (92140, 92320) ;" sql <- "SELECT * FROM Localisation WHERE Ville IN ('CHATILLON', 'CLAMART') ;" Troncature impossible id Adresse Code Ville 1 2 rue Gay Lussac 92320 CHATILLON 2 3 rue Roissis 92140 CLAMART Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 BETWEEN Prédicats : LIKE, BETWEEN, IN, ISNULL rechercher entre deux bornes sql <- "SELECT * FROM Localisation WHERE Code BETWEEN 92140 AND 92200 ;" id Adresse Code Ville 1 1 avenue Verdun 92170 VANVES 2 3 rue Roissis 92140 CLAMART Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 NOT … Prédicats : LIKE, BETWEEN, IN, ISNULL Les commandes LIKE, IN et BETWEEN peuvent être utilisées avec le préfixe NOT sql <- "SELECT * FROM Localisation WHERE Ville NOT LIKE '%N%' ;" id Adresse Code Ville 1 3 rue Roissis 92140 CLAMART Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 IS NULL Prédicats : LIKE, BETWEEN, IN, ISNULL rechercher des valeurs nulles sql <- "SELECT Nom, Prénom FROM Personnes WHERE ISNULL (Téléphone);" # NOT ISNULL () sqlQuery(channel,sql) Nom Prénom 1 Meyer Michel sqldf(sql) # erreur sql <- "SELECT Nom, Prénom FROM Personnes WHERE Téléphone ISNULL;" sqldf(sql) Nom Prénom 1 Meyer Michel sqlQuery(channel,sql) # erreur sql <- "SELECT Nom, Prénom FROM Personnes WHERE Téléphone IS NULL;" # IS NOT NULL sqldf(sql) sqlQuery(channel,sql) Nom Prénom 1 Meyer Michel sql <- "SELECT Nom, Prénom FROM Personnes WHERE NOT Téléphone IS NULL;" 24/04/2012 opérateurs logiques OR, AND, NOT OR, AND, NOT Lier les conditions de recherche OR sql <- "SELECT * FROM Localisation WHERE Adresse Like '%s' OR Adresse Like '%n' ;" id Adresse Code Ville 1 1 avenue Verdun 92170 VANVES 2 3 rue Roissis 92140 CLAMART AND sql <- "SELECT * FROM Localisation WHERE Ville LIKE 'c%' AND Code > 92200 ;" id Adresse Code Ville 1 2 rue Gay Lussac 92320 CHATILLON NOT sql <- "SELECT * FROM Localisation WHERE NOT ville = 'VANVES' ;" # avec sqldf(sql) utilisation possible de != id Adresse Code Ville 1 2 rue Gay Lussac 92320 CHATILLON 2 3 rue Roissis 92140 CLAMART sql <- "SELECT * FROM Localisation WHERE NOT Code = 92320 ;" # idem avec sql <- "SELECT * FROM Localisation WHERE Code <> 92320 ;" id Adresse Code Ville 1 1 avenue Verdun 92170 VANVES 2 3 rue Roissis 92140 CLAMART Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 GROUP BY Aggrégation des lignes Permet faire un dénombrement (count) ou le calcul d'une fonction d'aggrégation pour les champs des lignes regroupées. Critères d'aggrégation : min, max, avg, sum ou une expression Exemples : Nombre d'enregistrements par commune sql <- "SELECT Ville, count(*) AS Nb_personnes FROM Habitants GROUP BY Ville ;" Ville Nb_personnes 1 CHATILLON 5 2 CLAMART 5 3 VANVES 3 Moyenne des numéros par commune sql <- "SELECT Ville, avg(numéro) AS Moy FROM Habitants GROUP BY Ville ;" Ville Moy 1 CHATILLON 11.400000 2 CLAMART 19.000000 3 VANVES 3.666667 Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 GROUP BY Réaliser un tableau de contingence Nombre de téléphones par famille et par communes sql <- "SELECT Nom, sum(Ville = 'CHATILLON') AS CHATILLON, sum(Ville = 'CLAMART') AS CLAMART, sum(Ville = 'VANVES') AS VANVES FROM Habitants GROUP BY Nom, Ville ;" 1 2 3 4 5 6 7 8 9 Nom CHATILLON CLAMART VANVES Auquier 0 3 0 Berrue 0 0 2 Foucher 0 1 0 Larrouy 2 0 0 Lecesve 1 0 0 Lipinski 1 0 0 Mahier 0 0 1 Malher 1 0 0 Meyer 0 1 0 sel <- sqldf("SELECT Nom, Ville FROM Habitants ;") ( tab <- table(sel) ) # class 'table' str(tab) as.data.frame(tab) # Résultat non attendu ! Pourquoi ? class(tab) <- "matrix" as.data.frame(tab) # C'est mieux tabsql <- sqldf(sql) str(tabsql) 'data.frame': 9 obs. of 4 variables: $ Nom : Factor w/ 9 levels "Auquier","Berrue",..: $ CHATILLON: int 0 0 0 2 1 1 0 1 0 $ CLAMART : int 3 0 1 0 0 0 0 0 1 $ VANVES : int 0 2 0 0 0 0 1 0 0 rownames(tabsql) <- tabsql[,1] (tabsql <- tabsql[,-1]) Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 HAVING Clause " Where" d'un GROUP BY Permet d'introduire une condition dans un GROUP BY Exemple : Qui a plus d'un téléphone dans les villes ayant un CP > 92150 ? sql <- "SELECT Nom, Prénom, Count(Téléphone) AS NbTéléphone FROM Habitants WHERE Code > 92150 GROUP BY Nom, Prénom HAVING Count (Téléphone) >= 2 ;" Nom Prénom NbTéléphone 1 Berrue Christiane 2 Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 Jointure entre tables 1 - Jointure interne 1.1 - Equi-jointure : relier avec une relation d'égalité des tables par un champ commun Dans la clause WHERE sql <- "SELECT Nom, Prénom, Ville FROM Localisation, Personnes WHERE Localisation.id = id_localisation ;" Dans le FROM avec INNER JOIN ... ON sql <- "SELECT Nom, Prénom, Ville FROM Localisation INNER JOIN Personnes ON Localisation.id = id_localisation ;" 1 2 3 4 5 6 7 8 9 10 11 12 13 Nom Prénom Ville Mahier Ludovic VANVES Berrue Christiane VANVES Berrue Christiane VANVES Lecesve André CHATILLON Larrouy Catherine CHATILLON Larrouy Eric CHATILLON Malher Goerges CHATILLON Lipinski Ludovic CHATILLON Meyer Michel CLAMART Foucher Georges CLAMART Auquier Anne CLAMART Auquier Anne CLAMART Auquier Bernard CLAMART Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 Jointure entre tables 1 - Jointure interne 1.2 - Auto-jointure : jointure d'une table avec elle-même Utilisation obligatoire d'un alias Rechercher des champs qui se trouvent à l'intérieur d'une même table. Exemple : Qui partage le même téléphone ? sql <- "SELECT a.Nom, a.Prénom, a.Téléphone FROM Habitants a, Habitants b WHERE a.id <> b.id AND a.Téléphone = b.Téléphone;" Nom Prénom Téléphone 1 Larrouy Catherine 140920841 2 Larrouy Eric 140920841 Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 Jointure entre tables 1 - Jointure interne 1.3 - Théta jointure : jointure avec un opérateur de comparaison autre que = Utilisation possible de : supérieur (>), inférieur (<), supérieur ou égal (>=), inférieur ou égal (<=), différent (<>). Exemple : Dans un ordre alphabétique, combien de villes sont après chaque ville ? sql <- "SELECT a.Ville, COUNT(*) AS Reste FROM Localisation a, Localisation b WHERE a.Ville < b.Ville GROUP BY a.Ville;" Ville Reste 1 CHATILLON 2 2 CLAMART 1 La liste est-elle complète ? Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 Jointure entre tables Remarques 1/2 Une jointure sans clause WHERE réalise produit cartésien des tables impliquées sql <- "SELECT count(*) FROM Localisation, Personnes ;" count(*) 1 39 Vérification : sqldf ("SELECT count(*) FROM Personnes;") * sqldf("SELECT count(*) FROM Localisation;") count(*) 1 39 Nom Prénom Téléphone Une jointure sur des champs non uniques réalise le produit entre ces champs sql <- "SELECT P.Nom, P.Prénom, P.Téléphone FROM Personnes P, Habitants H WHERE P.Nom= H.Nom AND P.Prénom= H.Prénom;" Comment éliminer ces doublons ? Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 1 Lecesve André 146542856 2 Larrouy Catherine 140920841 3 Larrouy Eric 140920841 4 Malher Goerges 146576986 5 Lipinski Ludovic 147352329 6 Meyer Michel NA 7 Foucher Georges 146449501 8 Auquier Anne 157750048 9 Auquier Anne 157750048 10 Auquier Anne 636699001 11 Auquier Anne 636699001 12 Auquier Bernard 146428564 13 Mahier Ludovic 147361266 14 Berrue Christiane 146381434 15 Berrue Christiane 146381434 16 Berrue Christiane 954912355 17 Berrue Christiane 954912355 24/04/2012 Jointure entre tables Remarques 2/2 Jointure sur des champs contenant des valeurs nulles (NULL) sql <- "SELECT P.Nom, P.Prénom, P.Téléphone FROM Personnes P, Habitants H WHERE P.Nom= H.Nom AND P.Prénom= H.Prénom AND P.Téléphone = H.Téléphone;" ou sql <- "SELECT P.Nom, P.Prénom, P.Téléphone FROM Personnes P inner join Habitants H ON P.Nom= H.Nom AND P.Prénom= H.Prénom AND P.Téléphone = H.Téléphone;" Nom Prénom Téléphone 1 Lecesve André 146542856 2 Larrouy Catherine 140920841 3 Larrouy Eric 140920841 4 Malher Goerges 146576986 5 Lipinski Ludovic 147352329 6 Foucher Georges 146449501 7 Auquier Anne 157750048 8 Auquier Anne 636699001 9 Auquier Bernard 146428564 10 Mahier Ludovic 147361266 11 Berrue Christiane 146381434 12 Berrue Christiane 954912355 Dans ce cas, il manque un nom car : Meyer Michel n'a pas de téléphone Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 Jointure entre tables 2 – Jointure externe { LEFT | (RIGHT } OUTER JOIN : pour inclure tous les enregistrements d'une table et seulement ceux de l'autre table pour lesquels les champs joints sont égaux. FULL OUTER JOIN : Exemple : pour inclure les enregistrements pour lesquels les champs joints sont égaux ou ont des valeurs nulles. Utile quand les champs joints ont des valeurs nulles Habitants LEFT OUTER JOIN Comm2 ON Habitants.Code = Comm2.Code sql <- "SELECT Habitants.Nom, Habitants.Prénom, Comm2.Ville FROM Habitants LEFT OUTER JOIN Comm2 ON Habitants.Code = Comm2.Code;" 24/04/2012 Jointure entre tables 2 – Jointure externe LEFT OUTER JOIN sql <- "SELECT Personnes.Nom, Personnes.Prénom, Personnes.Téléphone FROM Personnes LEFT OUTER JOIN Habitants ON Personnes.Nom = Habitants.Nom AND Personnes.Prénom = Habitants.Prénom AND Personnes.Téléphone = Habitants.Téléphone ;" Nom Prénom Téléphone 1 Lecesve André 146542856 2 Larrouy Catherine 140920841 3 Larrouy Eric 140920841 4 Malher Goerges 146576986 5 Lipinski Ludovic 147352329 6 Meyer Michel NA 7 Foucher Georges 146449501 8 Auquier Anne 157750048 9 Auquier Anne 636699001 10 Auquier Bernard 146428564 11 Mahier Ludovic 147361266 12 Berrue Christiane 146381434 13 Berrue Christiane 954912355 RIGHT OUTER JOIN Résultat identique avec : sql <- "SELECT P.Nom, P.Prénom, P.Téléphone FROM Personnes P, Habitants H WHERE (P.Nom= H.Nom AND P.Prénom= H.Prénom) AND (P.Téléphone = H.Téléphone OR P.Téléphone is null;" Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) sql <- "SELECT Personnes.Nom, Personnes.Prénom, Personnes.Téléphone FROM Habitants RIGHT OUTER JOIN Personnes ON Personnes.Nom = Habitants.Nom AND Personnes.Prénom = Habitants.Prénom AND Personnes.Téléphone = Habitants.Téléphone ;" Remarque : sqldf : RIGHT AND FULL OUTER JOINs are not currently supported MS Access : FULL OUTER JOIN n'existe pas 24/04/2012 SELECT imbriqués Permet d'utiliser dans la clause WHERE d'un SELECT le résultat d'un autre SELECT S'utilise souvent à la place d'une la jointure La sous requête peut retourner un sous ensemble de 0 à n valeurs. En fonction de la condition de la clause WHERE du SELECT principal, on utilisera pour la liaison entre le champ du SELECT principal et les valeurs renvoyées par la sous requête : un des opérateurs de comparaison : =, >, <, >=, <=,<> un des prédicats : IN, ANY, ALL ou EXISTS SELECT ... WHERE champ { opérateurs | prédicats } (SELECT ... Suivant la condition souhaitée, le prédicat doit être : IN Réalise l'égalité avec un OU entre toutes valeurs ANY Vérifie si au moins une des valeurs satisfait la condition ALL Vérifier si toutes les valeurs satisfont la condition EXISTS La condition est VRAIE si n valeurs retournées > 0, FAUSSE si n = 0 24/04/2012 Corrélation SELECT imbriqués Cas particulier : Quand une condition fait intervenir le même champ de la même table Utilisation obligatoire d'alias Exemple : Nom des habitants dont l'adresse est dans la première moitié de la rue sql <- "SELECT a.Nom, a.prénom, a.numéro, a.Adresse FROM Habitants a WHERE a.numéro <= (SELECT avg(b.numéro) FROM Habitants b GROUP BY Adresse HAVING b.Adresse = a.Adresse) ;" 1 2 3 4 5 6 Nom Prénom numéro Adresse Lecesve André 9 rue Gay Lussac Larrouy Catherine 10 rue Gay Lussac Larrouy Eric 10 rue Gay Lussac Meyer Michel 15 rue Roissis Foucher Georges 17 rue Roissis Mahier Ludovic 3 avenue Verdun corrélation Exécution de la requête SQL : sqldf (sql) sqlQuery (channel, sql) 24/04/2012 IN, EXISTS SELECT imbriqués Exemples d'utilisation IN pour tester l'égalité avec toutes valeurs prises une par une (OU) Dans quelle(s) rue(s) des habitants n'ont pas de téléphone ? sql <- "SELECT Adresse, Ville FROM Localisation WHERE id IN (SELECT id_localisation FROM Personnes WHERE Téléphone IS NULL ) ;" Quel(s) habitant(s) ont la même ancienneté qu'Eric Larrouy ? sql <- "SELECT DISTINCT Nom, Prénom , Depuis FROM Personnes WHERE Depuis IN ( SELECT Depuis FROM Personnes WHERE nom = 'Larrouy' AND Prénom ='Eric' ) AND NOT (nom = 'Larrouy' AND Prénom ='Eric') ;" # Avec une corrélation et EXISTS Pourquoi DISTINCT ? sql <- "SELECT DISTINCT Nom, Prénom , Depuis FROM Personnes a WHERE EXISTS ( SELECT * FROM Personnes b WHERE b.nom = 'Larrouy' AND b.Prénom ='Eric' AND b.Depuis = a.Depuis ) Exécution requête : AND NOT (a.nom = 'Larrouy' AND a.Prénom ='Eric') ;" sqldf (sql) 24/04/2012 sqlQuery (channel, sql) ANY, ALL SELECT imbriqués Exemples d'utilisation Quels habitants ont une ancienneté identique ou plus faible de celle d'Eric Larrouy ? ANY pour tester si au moins une des valeurs satisfait la condition sql <- "SELECT DISTINCT Nom, Prénom , Depuis FROM Personnes WHERE Depuis >= ANY ( SELECT Depuis FROM Personnes WHERE nom = 'Larrouy' AND Prénom ='Eric' ) AND NOT (nom = 'Larrouy' AND Prénom ='Eric') ;" Quels habitants ont une ancienneté plus élevée que ceux de l'avenue Verdun à VANVES (92170) ALL pour tester si toutes les valeurs satisfont la condition sql <- "SELECT DISTINCT Nom, Prénom ,Ville, Depuis FROM Habitants WHERE Depuis < ALL ( SELECT Depuis FROM Habitants WHERE Adresse = 'avenue Verdun' AND Code = 92170 ) ;" # comparer le résultat en utilisant ANY Exécution requête : sqldf (sql) sqlQuery (channel, sql) Habitants Vanves Depuis 1 1983-05-07 2 1985-10-21 3 1985-10-21 24/04/2012 UNION Pour fusionner les lignes issues de deux requêtes Les requêtes doivent impérativement retourner des lignes de composition identique : même champs à la même position sql1 <- "SELECT DISTINCT Ville, Code FROM Localisation WHERE Ville LIKE 'c%' " sqldf(sql1) Ville Code 1 CHATILLON 92320 2 CLAMART 92140 Faire attention au ; qui doit être absent de la première requête sql2 <- "SELECT DISTINCT Ville, Code FROM Habitants WHERE NOT Ville LIKE 'c%' ;" sqldf(sql2) Ville Code 1 VANVES 92170 Ville Code 1 CHATILLON 92320 2 CLAMART 92140 3 VANVES 92170 (non obligatoire avec ACCESS) Union des requêtes sql1 et sql2 sql <- paste (sql1, "UNION", sql2) sqldf(sql) Et avec sql2 <- "SELECT DISTINCT Ville, Code, numéro FROM Habitants WHERE NOT Ville LIKE 'c%'" sqlQuery(channel,sql) # [1] "[RODBC] ERROR: Could not SQLExecDirect" sqldf(sql) # Erreur dans sqliteExecStatement 24/04/2012 INTERSECT Sélection des lignes communes aux deux requêtes S'utilise comme UNION sql1 <- "SELECT Ville, Code FROM Localisation" sqldf(sql1) sql2 <- "SELECT Ville, Code FROM Comm2" sqldf(sql2) Intersection des requêtes sql1 et sql2 sql <- paste(sql1,"INTERSECT",sql2) sqldf (sql) Ville Code 1 CHATILLON 92320 2 CLAMART 92140 3 MALAKOFF 92240 Ville Code 1 VANVES 92170 2 CHATILLON 92320 3 CLAMART 92140 Ville Code 1 CHATILLON 92320 2 CLAMART 92140 sqlQuery(channel,sql) # [1] "[RODBC] ERROR Si non implémenté dans le SQBDR Utiliser des requêtes imbriquées Utiliser des jointures ... 24/04/2012 INTERSECT Si non implémenté dans le SQBDR Comment faire ? En utilisant des jointures sql <- "SELECT L.Ville, L.Code FROM Localisation L, Comm2 C WHERE L.Ville = C.Ville AND L.Code = C.Code ;" Utiliser des requêtes imbriquées Exécution requête : sqldf (sql) sqlQuery (channel, sql) sql <- "SELECT * FROM Comm2 C WHERE EXISTS (SELECT * FROM Localisation L WHERE L.Ville = C.Ville AND L.Code = C.Code) ;" De même : sql <- "SELECT L.Ville, L.Code FROM Localisation L WHERE EXISTS (SELECT * FROM Comm2 C WHERE L.Ville = C.Ville AND L.Code = C.Code) ;" 24/04/2012 EXCEPT Sélection des lignes différentes d'une requête par rapport à l'autre S'utilise comme UNION sql1 <- "SELECT Ville, Code FROM Localisation" sqldf(sql1) sql2 <- "SELECT Ville, Code FROM Comm2" sqldf(sql2) Ville Code 1 CHATILLON 92320 2 CLAMART 92140 3 MALAKOFF 92240 Ville Code 1 VANVES 92170 2 CHATILLON 92320 3 CLAMART 92140 Lignes de sql1 non dans sql2 sql <- paste(sql1,"EXCEPT",sql2) Lignes de sql2 non dans sql1 sql <- paste(sql2,"EXCEPT",sql1) sqldf (sql) sqldf (sql) Ville Code 1 VANVES 92170 sqlQuery(channel,sql) # [1] "[RODBC] ERROR Si non implémenté dans le SQBDR Ville Code 1 MALAKOFF 92240 Utiliser des requêtes imbriquées Utiliser des jointures ... 24/04/2012 EXCEPT Si non implémenté dans le SQBDR Comment faire ? En utilisant des jointures # Communes de Localisation non présentent dans Comm2 sql1 <- "SELECT L.Ville, L.Code FROM Localisation L LEFT JOIN Comm2 C ON L.Ville = C.Ville AND L.Code = C.Code WHERE C.Code IS NULL ;" Ville Code 1 VANVES 92170 Avec LEFT JOIN # Communes de Comm2 non présentent dans Localisation sql2 <- "SELECT C.Ville, C.Code FROM Comm2 C LEFT JOIN Localisation L ON L.Ville = C.Ville AND L.Code = C.Code WHERE L.Code IS NULL ;" Ville Code 1 MALAKOFF 92240 En utilisant des requêtes imbriquées Exécution requête : sqldf (sql1) sqlQuery (channel, sql1) # Communes de Localisation non présentent dans Comm2 sql1 <- "SELECT L.Ville, L.Code FROM Localisation L WHERE NOT EXISTS (SELECT * FROM Comm2 C WHERE L.Ville = C.Ville AND L.Code = C.Code);" Ville Code 1 VANVES 92170 # Communes de Comm2 non présentent dans Localisation sql2 <- "SELECT * FROM Comm2 C WHERE NOT EXISTS (SELECT * FROM Localisation L WHERE L.Ville = C.Ville AND L.Code = C.Code);" id Ville Code 1 3 MALAKOFF 92240 sqldf(paste(sql1, "UNION", sql2)) 24/04/2012 Commande DELETE pour supprimer des lignes d'une table Syntaxe DELETE * FROM table [alias] [ WHERE { conditions de recherche | sous conditions} ] ; # Création de la table de travail Personne2 Personnes <- sqlQuery(channel,"SELECT * FROM Personnes;") sqlSave(channel, Personnes[,-7],"Personne2",rownames=FALSE) sqlQuery(channel,"SELECT * FROM Personne2;") Légende : { } : Une des valeurs séparées par '|' obligatoire. [ ] : Valeur optionnelle. Exemples Suppression dans la table Personne2 des lignes où le champ Téléphone est nul sql <- "DELETE * FROM Personne2 WHERE Téléphone IS NULL" Suppression de toutes les lignes de la table Personne2 sql <- "DELETE * FROM Personne2 Exécution requête : sqlQuery (channel, sql) Remarque : la définition de la table est conservée # Vérification sqlQuery (channel, "SELECT * FROM Personne2;") 24/04/2012 Commande INSERT pour insérer des lignes dans une table Syntaxe INSERT INTO table [ (col [, col ] ...)] { VALUES ( val [, val ] ...) | SELECT } Exemple Légende : { } : Une des valeurs séparées par '|' obligatoire. [ ] : Valeur optionnelle ... : Répétition Insérer dans la table Personne2 le contenu des champs Nom, Prénom, numéro, id_localisation, Téléphone à partir de la table Personnes pour les habitants de Clamart. sql <- "INSERT INTO Personne2 ( Nom, Prénom, numéro, id_localisation, Téléphone ) SELECT DISTINCT P.Nom, P.Prénom, P.numéro, P.id_localisation, P.Téléphone FROM Localisation L, Personnes P WHERE L.id = P.id_localisation AND L.Ville='CLAMART' ;" Exécution requête : sqlQuery (channel, sql) # Vérification sqlQuery (channel, "SELECT * FROM Personne2;") # Que remarque-t-on et pourquoi ? (afficher Habitants) 24/04/2012 Commande UPDATE pour modifier le contenu des champs d'une table Syntaxe UPDATE table [alias] [ INNER JOIN . ON ] SET { col = expr [, col = expr ] ... | ( col [, col ] ... ) = ( SELECT ) } [ WHERE conditions de recherche ] Exemples Légende : { } : Une des valeurs séparées par '|' obligatoire. [ ] : Valeur optionnelle ... : Répétition Mettre 999 dans le champ id de la table Personne2 pour Foucher sql <- "UPDATE Personne2 SET id = '999' WHERE Nom ='Foucher' " Mettre à jour le champ id de la table Personne2 à partir de la table Personnes. sql <- "UPDATE Personne2 INNER JOIN Personnes ON (Personne2.Téléphone = Personnes.Téléphone) AND (Personne2.Prénom = Personnes.Prénom) AND (Personne2.Nom = Personnes.Nom) SET Personne2.id = Personnes.id ;" Exécution requête : sqlQuery (channel, sql) # Vérification sqlQuery (channel, "SELECT * FROM Personne2;") (afficher Habitants) 24/04/2012 Commande CREATE TABLE pour créer une table DDL Syntaxe CREATE TABLE table ( col datatype [DEFAULT expr] [constraint] [ , col datatype [DEFAULT expr] [constraint] ... ] ) Légende : [ ] : Valeur optionnelle ... : Répétition Exemple Créer la table New avec deux colonnes sql <- "CREATE TABLE New (col1 varchar(20), col2 integer) ;" sqlQuery (channel,sql) # Vérification sqlColumns (channel, "New")[, 3:7] Exécution requête : sqlQuery (channel, sql) TABLE_NAME COLUMN_NAME DATA_TYPE TYPE_NAME COLUMN_SIZE 1 New col1 12 VARCHAR 20 2 New col2 4 INTEGER 10 24/04/2012 Commande DROP TABLE pour supprimer une table DDL Syntaxe DROP TABLE table # Lister le nom des tables de la base sqlTables (channel)$TABLE_NAME [-c(1:6)] Exemple Supprimer les tables New et Personne2 sql <- "DROP TABLE New ;" sql <- "DROP TABLE Personne2 ;" Exécution requête : sqlQuery (channel, sql) # Vérification sqlTables(channel)$TABLE_NAME[-c(1:6)] 24/04/2012 Exercice Créer une table "communes" à partir de la table "localisation" avec uniquement les communes CHATILLON et CLAMART et en y ajoutant MALAKOFF (92240). La table commune n'a que les champs "Ville" et "Code". 24/04/2012 Exercice Créer une table "communes" à partir de la table "localisation" avec uniquement les communes CHATILLON et CLAMART et en y ajoutant MALAKOFF (92240). La table commune n'a que les champs "Ville" et "Code". # 1 - Création de la table comex à partir d'un SELECT sql <- "SELECT DISTINCT Ville, Code FROM Localisation WHERE Ville LIKE 'c%';" sqlCopy(channel, sql, "comex",rownames="id", addPK=TRUE) # par défaut, dans la base sqlQuery(channel,"SELECT * FROM comex ;") # Vérification # 2 - Création du data.frame avec la nouvelle commune à ajouter newcom <- as.data.frame(cbind("MALAKOFF","92240")) str(newcom ) # Problèmes : factor newcom [,1] <- as.character(newcom[,1]) newcom [,2] <- as.integer(as.character(newcom[,2])) # Obligatoire : colnames(newcom) <- c("Ville","Code") # noms champs de la table rownames(newcom) <- "3" # bonne valeur de l'index ("id") # 3 - Ajout du data.frame à la table sqlSave(channel, newcom ,tablename ="comex", rownames = "id", addPK = TRUE, append = TRUE) # Vérification sqlQuery(channel,"SELECT * FROM comex ;") 24/04/2012