只是想知道是否可以使用DBI将参数传递给SQL查询IN子句?尝试了以下(以及许多变体,包括未命名的参数)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "iris", iris)
iris_result <- dbSendQuery(con, "SELECT * FROM iris WHERE [Petal.Width] > $PW and [Petal.Length] in ($PL)")
dbBind(iris_result, list(PW=2.3, PL={6.0, 5.1}))
dbFetch(iris_result)
此链接Parameterized Queries显示了使用胶水包的方法,但是,我想知道是否可以只使用DBI。
感谢。
注意,作为参考,这里是使用glue的方法:
rs_sql <- glue_sql("SELECT * FROM iris WHERE [Petal.Width] > {pwin} and [Petal.Length] IN ({lengths*})",
pwin = 2.3, lengths = c(6.0, 5.1),
.con = con
)
iris_result <- dbSendQuery(con, rs_sql)
dbFetch(iris_result)
rs_sql <- glue_sql("SELECT * FROM iris WHERE [Petal.Width] > {pwin} and [Species] IN ({species*})",
pwin = 2.3,
species = c('virginica'),
.con = con
)
iris_result <- dbSendQuery(con, rs_sql)
dbFetch(iris_result)
答案 0 :(得分:1)
如果您想使用一个参数使用IN
在SQL的dbBind()
子句中绑定未定义数量的实际值:您可以&#39 ;!吨强>
library(RSQLite)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "iris", iris)
iris_result <- dbSendQuery(con, "SELECT * FROM iris WHERE [Petal.Width] > $PW and [Petal.Length] in ($PL)")
dbBind(iris_result, list(PW=2.3, PL=list(6.0, 5.1)))
# Error in rsqlite_bind_rows(res@ptr, params) : Parameter 2 does not have length 1.
仅当您为IN
子句的每个元素定义一个参数时才有效,请参阅SQLite的语法图:
IN
元素的数量始终相同):可能的解决方法是预先定义一些参数,并始终在dbBind
中为它们提供值。
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "iris", iris)
# Works only if you know the number of IN-elements in adavance...
iris_result <- dbSendQuery(con, "SELECT * FROM iris WHERE [Petal.Width] > $PW and [Petal.Length] in ($PL1, $PL2)")
dbBind(iris_result, list(PW=2.3, PL1=6.0, PL2=5.1))
dbFetch(iris_result)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 6.3 3.3 6.0 2.5 virginica
# 2 5.8 2.8 5.1 2.4 virginica
IN
元素的数量正在改变):您还可以计算实际参数的数量,并在IN
子句中生成相同数量的查询参数,然后使用dbSendQuery
准备SQL查询。这可以防止SQL代码注入:
in.params <- c(PL1=6.0, PL2=5.1, PL3=5.6)
sql <- paste0("SELECT * FROM iris WHERE [Petal.Width] > $PW and [Petal.Length] in (",
paste0("$", names(in.params), collapse = ", "),
")")
iris_result <- dbSendQuery(con, sql)
dbBind(iris_result, c(list(PW=2.3), in.params))
dbFetch(iris_result)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 6.3 3.3 6.0 2.5 virginica
# 2 5.8 2.8 5.1 2.4 virginica
# 3 6.3 3.4 5.6 2.4 virginica
# 4 6.7 3.1 5.6 2.4 virginica
但这也意味着不重用已准备好的语句,如果这不是您想要的,那么只有SQL语句的经典字符串连接:
如果不使用glue
包,您只能自己连接SQL字符串,并尝试在(坏)用户输入参数值时尽量减少SQL代码注入的风险。
您可以使用dbQuote*
中的DBI
函数(RSQLite
符合DBI接口)...
答案 1 :(得分:0)
列表中的两个元素必须具有相同的长度。来自?dbBind
中的值部分:
绑定太多或没有足够的值,或者名称错误或长度不等的参数也会引发错误。如果命名查询中的占位符,则所有参数值必须具有名称(不能为空或NA),反之亦然,否则会引发错误。
进一步在?dbBind
中的规范:
此列表中的所有元素必须具有相同的长度并包含后端支持的值
以下内容适用于我:
library(RSQLite)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "iris", iris)
iris_result <- dbSendQuery(con, "SELECT * FROM iris WHERE [Petal.Length] = $PL and [Petal.Width] > $PW")
pl <- c(6.0, 5.1)
dbBind(iris_result, list(PL=pl, PW=rep(2.3, length(pl))))
dbFetch(iris_result)