Search code examples
rsqliter-glue

Way to use glue_sql() and avoid paste in dynamic SELECT statement?


I'm learning how to query SQLite dbs from R, and building those queries with glue_sql(). Below is a simplified example of a sub-query from my workflow. Is there a way I can create s10_wtX and s20_wtX without using paste0(), as in the code below?

library(DBI)
library(dplyr)
library(glue)

# example database
set.seed(1)
ps <- data.frame(plot = rep(1:3, each = 4),
                 spp = rep(1:3*10, 2),
                 wtX = rnorm(12, 10, 2) %>% round(1))
con <- dbConnect(RSQLite::SQLite(), "")
dbWriteTable(con, "ps", ps)

# species of interest
our_spp <- c(10, 20)

# for the spp of interest, sum wtX on each plot
sq <- glue_sql(paste0(
  'SELECT ps.plot,\n',
  paste0('SUM(CASE WHEN ps.spp = ', our_spp,
         ' THEN (ps.wtX) END) AS s', our_spp,
         '_wtX',
         collapse = ',\n'), '\n',
  '  FROM ps
    WHERE ps.spp IN ({our_spp*}) -- spp in our sample
    GROUP BY ps.plot'),
  .con = con)

# the result of the query should look like:
dbGetQuery(con, sq)
  plot s10_wtX s20_wtX
1    1    21.9    10.4
2    2    11.0    22.2
3    3     9.4    13.0

In my actual workflow, I have more than two species of interest, so I'd rather not fully write out each line (e.g., SUM(CASE WHEN ps.spp = 10 THEN (ps.wtX) END) AS s10_wtX).


Solution

  • The OP's original question is

    Is there a way I can create s10_wtX and s20_wtX without using paste0(), as in the code below?

    If we want to construct only with glue, use glue_collapse as well

    library(glue)
    sq1 <- glue_sql('SELECT ps.plot,', glue_collapse(glue('SUM(CASE WHEN ps.spp = {our_spp} THEN (ps.wtX) END) AS s{our_spp}_wtX'), sep = ",\n"), '\nFROM ps\n WHERE ps.spp IN ({our_spp*}) -- spp in our sample\n    GROUP BY ps.plot', .con = con)
    dbGetQuery(con, sq1)
      plot s10_wtX s20_wtX
    1    1    21.9    10.4
    2    2    11.0    22.2
    3    3     9.4    13.0