【问题标题】:Is there a 'cleaner' way to concatenate a query string?有没有一种“更干净”的方式来连接查询字符串?
【发布时间】:2020-01-25 00:21:10
【问题描述】:

我正在将查询字符串传递给连接,结果应如下所示:

select game_name, month, count(*) as count
  from device_metrics.mtu_events
 where YEAR = '2019' and month between '07' and '09'
 group by game_name, month
 order by game_name asc, month asc

如果我将上面的块作为单个字符串传递给DBI::dbGetQuery(con, myquery),这很好用

但是日期是闪亮应用程序中的一个变量,所以我尝试创建一个函数来生成查询字符串:

my_query <- function(start_date, end_date) {
        yr <- year(ymd(start_date))
        month_start <- month(ymd(start_date))
        month_end <- month(ymd(end_date))

        query <- paste0(
            "select game_name, month, count(*) as count
   from device_metrics.mtu_events
   where YEAR = ", yr, " and month between ", month_start, " and ", month_end, 
            " group by game_name, month
 order by game_name asc, month asc")

        return(query)
    }

当我调用这个函数并尝试用它查询我们的数据库时,我得到:

AWS Athena 客户端引发错误。 Athena 错误编号:372,HTTP 响应代码:1,错误消息:SYNTAX_ERROR: line 3:15: '=' cannot be applied to varchar, integer

有没有“正确”的方法来做到这一点?如何构造带有变量的查询字符串,然后传递给DBI::dbGetQuery()

【问题讨论】:

  • 我猜你需要where YEAR = '", yr, "' and month between '", month_start, "' and '", month_end, "' group_by grame_name, month,因为'yr'、'month_start'、'month_end'周围的单引号不在paste0
  • 那会是等价的吗?这进一步month_start &lt;- month(ymd(start_date)) %&gt;% str()
  • 我猜month(Sys.Date())返回数字试试my_query &lt;- function(start_date, end_date) { yr &lt;- year(ymd(start_date)) month_start &lt;- month(ymd(start_date)) month_end &lt;- month(ymd(end_date)) query &lt;- paste0( "select game_name, month, count(*) as count from device_metrics.mtu_events where YEAR = '", yr, "' and month between '", month_start, "' and '", month_end, "' group by game_name, month order by game_name asc, month asc") return(query) }
  • 坦率地说,我更愿意将DBI::dbBind 与参数化查询一起使用,而不是进行引用等(bobby-tables.com)。 (我对雅典娜的方言不熟悉,不知道它的支持情况如何。)
  • 关于参数化SQL查询herehere的一些想法

标签: r dbi rodbc dbplyr


【解决方案1】:

这里有两个选项,我们可以将输入作为字符串引用 ('),如 monthyear 函数返回数值

my_query <- function(start_date, end_date) {
        yr <- year(ymd(start_date))
        month_start <- month(ymd(start_date))
        month_end <- month(ymd(end_date))

        query <- paste0(
            "select game_name, month, count(*) as count
   from device_metrics.mtu_events
   where YEAR = '", yr, "' and month between '", month_start, "' and '", month_end, 
            "' group by game_name, month
 order by game_name asc, month asc")

        return(query)
    }

使用sprintf

my_query <- function(start_date, end_date) {
            yr <- year(ymd(start_date))
            month_start <- month(ymd(start_date))
            month_end <- month(ymd(end_date))

            query <- sprintf("select game_name, month, count(*) as count
       from device_metrics.mtu_events
       where YEAR = '%d'  and month between '%02d' and '%02d' group by game_name, month
     order by game_name asc, month asc", yr, month_start, month_end)

            return(query)
        }

【讨论】:

  • 我不会依赖手动刻度,sQuote 会更健壮的格式错误的参数(和 sql 注入)。
  • @r2evans 是的,但可能必须将您的花哨报价指定为 FALSE sQuote(1) [1] "‘1’"
  • 当然,但是options(useFancyQuotes = FALSE) 解决了这个问题。
【解决方案2】:

我们可以使用来自 gsubfn 的fn$ 来执行字符串插值。为了重现性,我们将使用 NULL 代替实际连接,使用 fn$list 代替 fn$dbGetQuery,但您可以同时替换两者。这样做时不要在名称中使用下划线或点。

library(gsubfn)

yr <- 2019
monthStart <- '07'
monthEnd <- '09'
con <- NULL

fn$list(con, "select game_name, month, count(*) as count
  from device_metrics.mtu_events
 where YEAR = '$yr' and month between '$monthStart' and '$monthEnd'
 group by game_name, month
 order by game_name asc, month asc")

可以分两步交替完成:

query <- fn$c("select game_name, month, count(*) as count
  from device_metrics.mtu_events
 where YEAR = '$yr' and month between '$monthStart' and '$monthEnd'
 group by game_name, month
 order by game_name asc, month asc")
dbGetQuery(con, query)

【讨论】:

    猜你喜欢
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    • 2019-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多