【问题标题】:Rmarkdown - evaluate or display the parametized query of an SQL chunkRmarkdown - 评估或显示 SQL 块的参数化查询
【发布时间】:2020-01-29 12:39:19
【问题描述】:

出于安全和可读性的原因,我在我的 Rmarkdown 文件中使用参数化 SQL 查询。

最终,我提供了包含动态表名称、动态参数甚至动态文本(使用逻辑评估变量)的查询,例如:
(感谢glue_sql(),可能已经定义了动态变量)

```{sql, output.var = "data"}
select * from ?table_name 
where color = ?color_value 
?if_I_want_names and name in (?names_choices) 
limit ?limit_value
'``

在长而复杂的参数化查询的情况下,访问完全“评估”的查询可能非常有用(用于检查和调试)。在我们的示例中,预期结果将是:

"从花中选择 *\n 其中颜色 = '红色' \n -- and name in ('rose', 'tulip')\n 限制 10 英寸

select * from flowers 
where color = 'red' 
-- and name in ('rose', 'tulip') 
limit 10

但我不知道该怎么做......玩块参数并没有帮助。还有其他选择吗?

【问题讨论】:

    标签: sql r r-markdown dbi


    【解决方案1】:

    最终,我想出了自己的答案。我会把它贴在这里,也许有一天对某人有用。

    我只是重新使用了来自knitr(可以找到here)的sql引擎函数的插值函数来定义我的函数:

    require('DBI')
    require('knitr')
    require('glue')
    
    # Return char vector of sql interpolation param names
    varnames_from_sql = function(conn = ANSI(), sql) {
      varPos = DBI::sqlParseVariables(conn, sql)
      if (length(varPos$start) > 0) {
        varNames = substring(sql, varPos$start, varPos$end)
        sub('^\\?', '', varNames)
      }
    }
    
    # Vectorized version of exists
    mexists = function(x, env = knit_global(), inherits = TRUE) {
      vapply(x, exists, logical(1), where = env, inherits = inherits)
    }
    
    # Interpolate a sql query based on the variables in an environment
    interpolate_from_env = function(conn = ANSI(), sql, env = knit_global(), inherits = TRUE) {
      names = unique(varnames_from_sql(conn, sql))
      names_missing = names[!mexists(names, env, inherits)]
      if (length(names_missing) > 0) {
        stop("Object(s) not found: ", paste('"', names_missing, '"', collapse = ", "))
      }
    
      args = if (length(names) > 0) setNames(
        mget(names, envir = env, inherits = inherits), names
      )
    
      do.call(DBI::sqlInterpolate, c(list(conn, sql), args))
    }
    

    然后,我可以将其称为我的 SQL 表达式以获得正确的 eval:

    interpolate_from_env(sql = "select * from ?table_name 
                                where color = ?color_value 
                                ?if_I_want_names and name in (?names_choices_sql)
                                limit ?limit_value")
    

    返回预期结果:

    从花中选择 *
    其中颜色 = '红色'
    -- 和名字在 ('rose', 'tulip')
    限制 10

    注意
    此方法需要使用glue_sql() 对您的变量进行适当的预评估。 在这种情况下:

    table_name <- glue_sql("flowers")
    color_value <- "red"
    names_choices <- 
    names_choices_sql <- glue_sql("{c("rose", "tulip")*}", # the {}* allows to collapse a vector in SQL format 
                                  .con = ANSI())
    if_I_want_names <- glue_sql("--")
    limit_value <- 10
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 2015-12-01
      • 1970-01-01
      相关资源
      最近更新 更多