dbGetQuery使用多个参数

huangapple go评论96阅读模式
英文:

dbGetQuery with multiple parameters

问题

我有一个问题。我想将**"querys1"作为参数传递给dbGetQuery**,但我无法获取我感兴趣的数据。然而,当我使用**"querys2""Filter2"运行dbGetQuery**时,我可以获取我的数据。

如何同时传递这两个Where子句?

感谢您的帮助。

英文:

I have a problem. I would like to pass "querys1" as parameters in dbGetQuery but I can't get the data I'm interested in. However, I can get my data when I run dbGetQuery with "querys2" and "Filter2".

  1. Filter1 <- "State" #input$state
  2. Filter2 <- "Luxury" #input$home
  3. query1 <-
  4. paste0(paste0("$", seq_along(Filter1)), collapse = ", ")
  5. query2 <-
  6. paste0(paste0("$", seq_along(Filter2)), collapse = ", ")
  7. querys1 <- paste0("SELECT *
  8. FROM table
  9. WHERE state IN (",
  10. query1,
  11. ") AND home IN (",
  12. query2,
  13. ")")
  14. querys2 <- paste0("SELECT *
  15. FROM table
  16. WHERE home IN (",
  17. query2,
  18. ")")
  19. data1 <- dbGetQuery(conn, querys2, as.list(Filter2))

How can I pass both Where clauses ?

Thank for your help.

答案1

得分: 2

问题在于您正在对每个过滤器进行序列化,而不是对所有过滤器进行序列化。我们可以看到这个问题在下面的代码中:

  1. querys1
  2. # [1] "SELECT *\n FROM table\n WHERE state IN ($1) AND home IN ($1)"

也就是说,这两个集合都是 $1。这意味着 statehome 被与相同的文字值进行比较,而不是每个向量的第一个值。$-数字需要在所有参数上进行序列化。

对于每个 Filter,长度为1,似乎很简单,但我推测它们可以是 "1个或多个",所以我们需要做更多的工作。

  1. query1 <-
  2. paste0(paste0("&quot;$&quot;", seq_along(Filter1)), collapse = "&quot;, &quot;)
  3. query2 <-
  4. paste0(paste0("&quot;$&quot;", length(Filter1) + seq_along(Filter2)), collapse = "&quot;, &quot;)
  5. querys1 <- paste0("&quot;SELECT *\n FROM table\n WHERE state IN (&quot;",
  6. query1,
  7. "&quot;) AND home IN (&quot;",
  8. query2,
  9. "&quot;)&quot;)
  10. querys2 <- paste0("&quot;SELECT *\n FROM table\n WHERE home IN (&quot;",
  11. query2,
  12. "&quot;)&quot;")

现在我们看到

  1. querys1
  2. # [1] &quot;SELECT *\n FROM table\n WHERE state IN ($1) AND home IN ($2)&quot;
  3. querys2
  4. # [1] &quot;SELECT *\n FROM table\n WHERE home IN ($2)&quot;

请注意,一旦您将 $ 嵌入查询中,您就必须包括与列表一样长的参数。因此,即使我们可能不使用 $1 参数,我们仍然需要在 params= 中包括它。

然后查询将如下所示:

  1. data1 <- dbGetQuery(conn, querys1, as.list(c(Filter1, Filter2)))
  2. data2 <- dbGetQuery(conn, querys2, as.list(c(Filter1, Filter2)))

如果您希望在 querys2 检索中不包括 Filter1,那么您需要重新制定 $-计数,不考虑 Filter1

另一种可以更自由地控制参数和 $ 引用的替代方法是使用一个辅助函数,将非计数占位符(如 ?,许多其他DBMS用于参数绑定的占位符)转换为 $ 计数,然后传递查询和参数列表,它将用 $ 计数替换 ? 文字。

我将稍微扩展这个函数,以处理 "IN" 1或多个向量。

  1. # @param query 长度为1的字符,带有 "?name" 命名绑定位置
  2. # @param params 命名参数列表,名称对应于 "?name" 绑定
  3. xlate <- function(query, params) {
  4. stopifnot(length(query) == 1L)
  5. gre <- gregexpr("\\?[A-Za-z]+", query)
  6. nms <- sub("^\\?", "", regmatches(query, gre)[[1]])
  7. newparams <- params[nms]
  8. leng <- lengths(newparams)
  9. leng <- c(0, leng[-length(leng)])
  10. qmarks <- mapply(function(pre, vec) {
  11. paste(paste0("$", pre + seq_along(vec)), collapse = ",")
  12. }, leng, newparams)
  13. newparams <- unname(unlist(newparams))
  14. regmatches(query, gre) <- list(qmarks)
  15. list(query = query, params = newparams)
  16. }

它的使用应该很直观:

  1. xlate("select * from table where state in (?st) or home in (?hm)", list(st="QQ", hm=c("abc","quux")))
  2. # $query
  3. # [1] "select * from table where state in ($1) or home in ($2,$3)"
  4. # $params
  5. # [1] "QQ" "abc" "quux"
  6. xlate("select * from table where home in (?hm)", list(st="QQ", hm=c("abc","quux")))
  7. # $query
  8. # [1] "select * from table where home in ($1,$2)"
  9. # $params
  10. # [1] "abc" "quux"
  11. xlate("select * from table where state in (?hm) or home in (?hm)", list(st="QQ", hm=c("abc","quux")))
  12. # $query
  13. # [1] "select * from table where state in ($1,$2) or home in ($3,$4)"
  14. # $params
  15. # [1] "abc" "quux" "abc" "quux"

这将用作:

  1. tmp <- xlate("select * from table where state in (?hm) or home in (?hm)", list(st="QQ", hm=c("abc","quux")))
  2. res <- dbGetQuery(con, tmp$query, params = tmp$params)
英文:

The problem is that you are sequencing along each of your filters instead of all of your filters. We can see why this is a problem with:

  1. querys1
  2. # [1] &quot;SELECT *\n FROM table\n WHERE state IN ($1) AND home IN ($1)&quot;

(That is, both sets are $1.) What this means is that state and home are compared against the same literal value, not the first of each vector. The $-numbers need to be sequencing along all parameters combined.

With length-1 for each of your Filters, it seems trivial, but I'm inferring they can be "1 or more", so we need to do a little more work.

  1. query1 &lt;-
  2. paste0(paste0(&quot;$&quot;, seq_along(Filter1)), collapse = &quot;, &quot;)
  3. query2 &lt;-
  4. paste0(paste0(&quot;$&quot;, length(Filter1) + seq_along(Filter2)), collapse = &quot;, &quot;)
  5. querys1 &lt;- paste0(&quot;SELECT *
  6. FROM table
  7. WHERE state IN (&quot;,
  8. query1,
  9. &quot;) AND home IN (&quot;,
  10. query2,
  11. &quot;)&quot;)
  12. querys2 &lt;- paste0(&quot;SELECT *
  13. FROM table
  14. WHERE home IN (&quot;,
  15. query2,
  16. &quot;)&quot;)

Now we see

  1. querys1
  2. # [1] &quot;SELECT *\n FROM table\n WHERE state IN ($1) AND home IN ($2)&quot;
  3. querys2
  4. # [1] &quot;SELECT *\n FROM table\n WHERE home IN ($2)&quot;

Recognize that once you embed $ in a query, you are beholden to having parameters of a list that long. So even though we may not be using the $1 parameter, we still need params= to include it.

The queries would then be:

  1. data1 &lt;- dbGetQuery(conn, querys1, as.list(c(Filter1, Filter2)))
  2. data2 &lt;- dbGetQuery(conn, querys2, as.list(c(Filter1, Filter2)))

If you prefer to not include Filter1 in your querys2 retrieval, then you need to reform the $-counting without Filter1 consideration.


One alternative to this where you can be a little looser in controlling the parameters and $-referencing is to use a helper function that converts a non-counting placeholder (such as ?, used by many other DBMSes for parameter binding), then pass the query and list of params, and it'll replace the ? literals with the $-counts.

I'll expand this a little to handle "IN" 1-or-more vectors.

  1. #&#39; @param query length-1 character, with &quot;?name&quot; named binding locations
  2. #&#39; @param params named list of params, names correspond to &quot;?name&quot; binds
  3. xlate &lt;- function(query, params) {
  4. stopifnot(length(query) == 1L)
  5. gre &lt;- gregexpr(&quot;\\?[A-Za-z]+&quot;, query)
  6. nms &lt;- sub(&quot;^\\?&quot;, &quot;&quot;, regmatches(query, gre)[[1]])
  7. newparams &lt;- params[nms]
  8. leng &lt;- lengths(newparams)
  9. leng &lt;- c(0, leng[-length(leng)])
  10. qmarks &lt;- mapply(function(pre, vec) {
  11. paste(paste0(&quot;$&quot;, pre + seq_along(vec)), collapse = &quot;,&quot;)
  12. }, leng, newparams)
  13. newparams &lt;- unname(unlist(newparams))
  14. regmatches(query, gre) &lt;- list(qmarks)
  15. list(query = query, params = newparams)
  16. }

And its use should be intuitive:

  1. xlate(&quot;select * from table where state in (?st) or home in (?hm)&quot;, list(st=&quot;QQ&quot;, hm=c(&quot;abc&quot;,&quot;quux&quot;)))
  2. # $query
  3. # [1] &quot;select * from table where state in ($1) or home in ($2,$3)&quot;
  4. # $params
  5. # [1] &quot;QQ&quot; &quot;abc&quot; &quot;quux&quot;
  6. xlate(&quot;select * from table where home in (?hm)&quot;, list(st=&quot;QQ&quot;, hm=c(&quot;abc&quot;,&quot;quux&quot;)))
  7. # $query
  8. # [1] &quot;select * from table where home in ($1,$2)&quot;
  9. # $params
  10. # [1] &quot;abc&quot; &quot;quux&quot;
  11. xlate(&quot;select * from table where state in (?hm) or home in (?hm)&quot;, list(st=&quot;QQ&quot;, hm=c(&quot;abc&quot;,&quot;quux&quot;)))
  12. # $query
  13. # [1] &quot;select * from table where state in ($1,$2) or home in ($3,$4)&quot;
  14. # $params
  15. # [1] &quot;abc&quot; &quot;quux&quot; &quot;abc&quot; &quot;quux&quot;

This would be used as:

  1. tmp &lt;- xlate(&quot;select * from table where state in (?hm) or home in (?hm)&quot;, list(st=&quot;QQ&quot;, hm=c(&quot;abc&quot;,&quot;quux&quot;)))
  2. res &lt;- dbGetQuery(con, tmp$query, params = tmp$params)

huangapple
  • 本文由 发表于 2023年6月15日 19:24:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76481966.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定