SQL databases often have custom quotation syntax for identifiers and strings
which make writing SQL queries error prone and cumbersome to do. glue_sql() and
glue_data_sql() are analogs to glue() and glue_data() which handle the
SQL quoting.
glue_sql(..., .con, .envir = parent.frame(), .na = DBI::SQL("NULL")) glue_data_sql(.x, ..., .con, .envir = parent.frame(), .na = DBI::SQL("NULL"))
| ... | [ |
|---|---|
| .con | [ |
| .envir | [ |
| .na | [ |
| .x | [ |
A DBI::SQL() object with the given query.
They automatically quote character results, quote identifiers if the glue
expression is surrounded by backticks ‘ and do not quote non-characters such as numbers. If numeric data is stored in a character column (which should be quoted) pass the data to ’glue_sql()` as a
character.
Returning the result with DBI::SQL() will suppress quoting if desired for
a given value.
Note parameterized queries are generally the safest and most efficient way to pass user defined values in a query, however not every database driver supports them.
If you place a * at the end of a glue expression the values will be
collapsed with commas. This is useful for the SQL IN Operator
for instance.
con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:") colnames(iris) <- gsub("[.]", "_", tolower(colnames(iris))) DBI::dbWriteTable(con, "iris", iris) var <- "sepal_width" tbl <- "iris" num <- 2 val <- "setosa" glue_sql(" SELECT {`var`} FROM {`tbl`} WHERE {`tbl`}.sepal_length > {num} AND {`tbl`}.species = {val} ", .con = con)#> <SQL> SELECT `sepal_width` #> FROM `iris` #> WHERE `iris`.sepal_length > 2 #> AND `iris`.species = 'setosa'# If sepal_length is store on the database as a character explicitly convert # the data to character to quote appropriately. glue_sql(" SELECT {`var`} FROM {`tbl`} WHERE {`tbl`}.sepal_length > {as.character(num)} AND {`tbl`}.species = {val} ", .con = con)#> <SQL> SELECT `sepal_width` #> FROM `iris` #> WHERE `iris`.sepal_length > '2' #> AND `iris`.species = 'setosa'# `glue_sql()` can be used in conjuction with parameterized queries using # `DBI::dbBind()` to provide protection for SQL Injection attacks sql <- glue_sql(" SELECT {`var`} FROM {`tbl`} WHERE {`tbl`}.sepal_length > ? ", .con = con) query <- DBI::dbSendQuery(con, sql) DBI::dbBind(query, list(num)) DBI::dbFetch(query, n = 4)#> sepal_width #> 1 3.5 #> 2 3.0 #> 3 3.2 #> 4 3.1DBI::dbClearResult(query) # `glue_sql()` can be used to build up more complex queries with # interchangeable sub queries. It returns `DBI::SQL()` objects which are # properly protected from quoting. sub_query <- glue_sql(" SELECT * FROM {`tbl`} ", .con = con) glue_sql(" SELECT s.{`var`} FROM ({sub_query}) AS s ", .con = con)#> <SQL> SELECT s.`sepal_width` #> FROM (SELECT * #> FROM `iris`) AS s# If you want to input multiple values for use in SQL IN statements put `*` # at the end of the value and the values will be collapsed and quoted appropriately. glue_sql("SELECT * FROM {`tbl`} WHERE sepal_length IN ({vals*})", vals = 1, .con = con)#> <SQL> SELECT * FROM `iris` WHERE sepal_length IN (1)glue_sql("SELECT * FROM {`tbl`} WHERE sepal_length IN ({vals*})", vals = 1:5, .con = con)#> <SQL> SELECT * FROM `iris` WHERE sepal_length IN (1, 2, 3, 4, 5)glue_sql("SELECT * FROM {`tbl`} WHERE species IN ({vals*})", vals = "setosa", .con = con)#> <SQL> SELECT * FROM `iris` WHERE species IN ('setosa')glue_sql("SELECT * FROM {`tbl`} WHERE species IN ({vals*})", vals = c("setosa", "versicolor"), .con = con)#> <SQL> SELECT * FROM `iris` WHERE species IN ('setosa', 'versicolor')# If you need to reference a table in a different schema use `DBI::Id()` to # construct the identifiers. cols <- c("Sepal.Width", "Sepal.Length", "Species") col_ids <- lapply(cols, function(x) DBI::Id(table="iris", column = x)) values <- c(1, 2, 'Setosa') glue_sql("INSERT ({values*}) INTO ({`col_ids`*})", .con=con)#> <SQL> INSERT ('1', '2', 'Setosa') INTO (`iris`.`Sepal.Width`, `iris`.`Sepal.Length`, `iris`.`Species`)