Skip to content

Commit

Permalink
New elements on databases (#439)
Browse files Browse the repository at this point in the history
* droits pour écrire dans base

* id et pwd dans .Renviron

* Ajout d'une mention sur les sous-requêtes (#436)

* complète fiche bdd (#435)

* droits pour écrire dans base
* id et pwd dans .Renviron

* petite correction de la hiérarchie des titres

* Relecture rmarkdown (#428)

* correction coquille orthographe

* Correction §27.4.2

* Déplacement logo Latex

* Modification éditeur markdown RStudio

* Correction coquille sur lien gif

* Changement url lancement du service utilitr dans CONTRIBUTING (#405)

* Changement url lancement du service utilitr dans CONTRIBUTING
* Update CONTRIBUTING.md

Co-authored-by: Pierre-Yves Berrard <[email protected]>

* ajout exemples de sous-requetes SQL

Co-authored-by: Pierre-Yves Berrard <[email protected]>
Co-authored-by: Lino Galiana <[email protected]>
Co-authored-by: Damien Dotta <[email protected]>

* Update bookdown-test.yaml

* Update Fiche_connexion_bdd.Rmd

Co-authored-by: Pierre-Yves Berrard <[email protected]>
Co-authored-by: Pierre Lamarche <[email protected]>
Co-authored-by: Pierre-Yves Berrard <[email protected]>
Co-authored-by: Damien Dotta <[email protected]>
  • Loading branch information
5 people authored Oct 4, 2022
1 parent 41afa68 commit 9ab53fa
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/bookdown-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
uses: actions/setup-node@v2
with:
node-version: '12'
node-version: '14'
- name: Deploy to Netlify
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
# NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID added in the repo's secrets
Expand Down
57 changes: 44 additions & 13 deletions 03_Fiches_thematiques/Fiche_connexion_bdd.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ La fonction `dbConnect` du _package_ `DBI` permet d'établir la connexion à la
Le *package* `RPostgres` fournit directement les *drivers* permettant de se connecter à une base de données PostgreSQL. Il s'installe facilement (pas de dépendance de librairies système) et la syntaxe pour une connexion est relativement simple. En revanche, ce *package* ne permet pas de visualiser facilement l'architecture de la base de données.

::: {.conseil}
Lorsqu'on découvre une base de données Postgres, il est fréquent de vouloir en visualiser l'architecture (liste des tables, liste des variables, schémas...). RStudio n'est pas très adapté sur ce point. Une très bonne alternative est le logiciel PgAdmin. Son utilisation est simple et il est en libre service sur Si@moi.
Lorsqu'on découvre une base de données `Postgres`,
il est fréquent de vouloir en visualiser l'architecture (liste des tables, liste des variables, schémas...).
`RStudio` n'est pas très adapté sur ce point.
Une très bonne alternative est le logiciel `PgAdmin`. Son utilisation est simple.
:::

Pour se connecter à une base de données Postgres avec `RPostgres`, il faut utiliser la fonction `dbConnect` de `DBI` avec les informations suivantes :
Expand Down Expand Up @@ -150,22 +153,38 @@ Pour lancer des requêtes sur la base de données, l'utilisateur a la possibilit
Ainsi, pour un utilisateur qui est connecté à la base de données PostgreSQL qui contient le schéma de diffusion - une sorte de librairie SAS - de Fidéli (`s_diff_2018`) et qui souhaite requêter la table des logements (`d_logement`) pour compter le nombre de logements par commune et selon le critère du type de local (critère n°2 dans la documentation utilisateur), on peut lancer les requêtes SQL suivantes :

```{r, eval = FALSE}
dbSendQuery(conn,
"create temp table count_log as
select csdep, cne,
case when natloc in ('MA', 'ME', 'AP') then 1 else 0 end as logement
from s_diff_2018.d_logement")
q <- dbSendQuery(conn,
"create temp table count_log as
select csdep, cne,
case when natloc in ('MA', 'ME', 'AP') then 1 else 0 end as logement
from s_diff_2018.d_logement")
dbClearResult(q)
count_log <- dbGetQuery(conn,
"select distinct concat(csdep, cne) as code_com,
sum(logement) as nb_logement
from count_log")
```

La première requête crée une table temporaire `count_log` qui contient le département et la commune de chaque local, ainsi qu'une variable indicatrice indiquant s'il s'agit d'un logement. Cette requête est envoyée au serveur avec `dbSendQuery` et ne renvoie donc aucun résultat vers `R`. La création de cette table temporaire nécessite d'avoir les droits en écriture dans la base.
La première requête crée une table temporaire `count_log` qui contient le département et la commune de chaque local, ainsi qu'une variable indicatrice indiquant s'il s'agit d'un logement. Cette requête est envoyée au serveur avec `dbSendQuery` et ne renvoie donc aucun résultat vers `R`. La création de cette table temporaire nécessite d'avoir les droits minimaux en écriture dans la base.

La seconde requête compte le nombre de logements par commune à partir de la table temporaire et renvoie vers `R` un objet de type `data.frame` appelé `count_log` donnant le nombre de logements (`nb_logement`) par commune (`code_com`).

Dans le cas où l'utilisateur n'a pas les droits pour créer des tables temporaires, il est toujours possible de procéder à des sous-requêtes (**sub-query**) en SQL. Cela consiste à enchasser la première requête dans la seconde sans passer par la création d'une table temporaire, de la manière suivante :

```{r, eval = FALSE}
q <- dbSendQuery(conn,
"select distinct concat(csdep, cne) as code_com,
sum(logement) as nb_logement
from (select csdep, cne,
case when natloc in ('MA', 'ME', 'AP') then 1 else 0 end as logement
from s_diff_2018.d_logement) as a")
dbFetch(q)
dbClearResult(q)
```

::: {.remarque}
Il est fréquent que les bases de données contiennent des données volumineuses, dont le téléchargement et le traitement peuvent dépasser les capacités de votre poste local. C'est pourquoi **il est recommandé d'éviter de télécharger les données brutes et de réaliser les traitements en `R`.** Dans la mesure du possible, **il vaut mieux faire exécuter les traitements par la base de données, et ne récupérer en `R` qu'un résultat agrégé.**

Expand All @@ -186,20 +205,32 @@ Une fois la référence créée, on peut manipuler les données de la table `d_l

```{r, eval = FALSE}
count_log <- d_logement %>%
mutate(logement = ifelse(natloc %in% c('MA', 'ME', 'AP'), 1, 0)) %>%
select(csdep, cne, logement) %>%
compute()
mutate(logement = ifelse(natloc %in% c('MA', 'ME', 'AP'), 1, 0)) %>%
select(csdep, cne, logement) %>%
compute()
count_log <- count_log %>%
group_by(csdep, cne) %>%
summarise(nb_logement = sum(logement)) %>%
collect()
group_by(csdep, cne) %>%
summarise(nb_logement = sum(logement)) %>%
collect()
```

Dans cet exemple, la nature de l'objet `count_log` change entre la première et la seconde instruction. Au départ, il s'agit d'une interprétation de l'instruction sous forme `dplyr` en requête SQL (un objet `sql_tbl`) stockée dans une table temporaire grâce à la commande `compute`, qui ensuite devient un objet `data.frame` suite à la commande `collect` (qui peut se voir comme un équivalent de la commande `dbGetQuery`, en plus large puisqu'elle déclenche la soumission de la requête SQL).

Le _package_ `dbplyr` présente l'avantage d'offrir une syntaxe très proche de celle de `dplyr`. Cette syntaxe peut néanmoins, comme indiqué dans la documentation, présenter des limites dans l'interprétation des commandes en requêtes SQL. L'utilisateur devra être particulièrement attentif à ce point.

L'enchâssement d'une sous-requête dans une requête SQL est très adapté au _pipe_ de la syntaxe `dplyr`, et se traduit très naturellement ainsi :

```{r, eval = FALSE}
count_log <- d_logement %>%
mutate(logement = ifelse(natloc %in% c('MA', 'ME', 'AP'), 1, 0)) %>%
select(csdep, cne, logement) %>%
group_by(csdep, cne) %>%
summarise(nb_logement = sum(logement)) %>%
collect()
```


::: {.conseil}
Comme indiqué ci-dessus, le _package_ `dbplyr` convertit automatiquement vos instructions en requête SQL. Il est possible d'afficher cette requête avec la fonction `show_query`. Cela vous permet de vous familiariser avec le langage SQL, et de voir que la requête SQL générée par `dbplyr` est souvent loin d'être optimale.
:::
Expand Down

0 comments on commit 9ab53fa

Please sign in to comment.