[英]Parameterized SQL query in R with IN clause
我正在嘗試通過Vertica DB的RODBC包獲取數據。 我目前有一個SQL查詢,如下所示。
library(rodbc) channel = odbcconnect("VerticaDB") query = paste
(
SELECT *
FROM item_history
WHERE item_exp_date BETWEEN ",x," AND ",y,"
AND item_code IN ('A1',
'A2',
'B1',
'B2')",sep="")result = (sqlQuery(channel,query)
)
我已經能夠參數化在“ BETWEEN”子句中傳遞的數據。 有沒有辦法我可以參數化在“ IN”類中傳遞的數據?
同樣,在“ IN”子句中傳遞的數據元素的數量也非常多(超過100個不同的項目)。
是否可以從外部Vector或文件中傳遞它?
您擁有的是SQL注入,而不是參數化查詢。 您可能需要查看RODBCext
軟件包及其小插圖 。
要正確地參數化查詢,您可以執行
library(RODBC)
library(RODBCext)
channel = odbcConnect("VerticaDB")
query = paste0("select * from Item_History ",
"where Item_Exp_Date between ? and ? ",
"and Item_Code = ?")
item <- c("A1", "A2", "B1", "B2")
x <- 3
y <- 10 # I don't actually know what your x and y are, but hopefully you get the idea
sqlExecute(
channel = channel,
query = query,
data = list(x = rep(x, length(item)),
y = rep(y, length(item)),
item = item),
fetch = TRUE,
stringsAsFactors = FALSE
)
但是,這樣做有很大的缺點,因為sqlExecute
將對data
參數中的每一行運行查詢(該列表將被強制到數據幀)。 如果item
向量中有數百個元素,則將在SQL實例上運行數百個查詢,這可能不是特別有效。
執行此操作的一種不太明顯的方法是編寫存儲過程以構造查詢。
您在SQL中的存儲過程可能看起來像
CREATE PROCEDURE schema.specialQuery
@x int;
@y int;
@in varchar(2000);
AS
BEGIN
DECLARE @query = varchar(8000);
SET @query = 'select * from Item_History ' +
'where Item_Exp_Date between ' + convert(@x, varchar(10)) +
' and ' + convert(@y, varchar(10)) +
' and Item_Code IN (' + @in ')'
EXEC @query
END
GO
您可能需要擺弄convert
函數和一些引號,但是它將與
sqlExecute(
channel = channel,
query = "EXECUTE schema.specialQuery @x = ?, @y = ?, @in = ?",
data = list(x = x,
y = y,
in = sprintf("'%s'", paste0(item, collapse = "', '"))),
fetch = TRUE,
stringsAsFactors = FALSE
)
不幸的是,這種方法仍然容易受到格式錯誤的字符串影響,這些字符串通過item
傳遞,但它可能比我展示的第一種方法運行數百個查詢要快。
要使用字符串操作(如問題所示):
x <- "2000-01-01"
y <- "2001-01-01"
Item_Code <- c('A1','A2','B1','B2')
query <- sprintf("select * from Item_History
where Item_Exp_Date between '%s' and '%s'
and Item_Code in (%s)", x, y, toString(shQuote(Item_Code, 'sh')))
我們可以選擇使用gsubfn包中的fn$
進行字符串插值:
library(gsubfn)
query2 <- fn$identity("select * from Item_History
where Item_Exp_Date between '$x' and '$y'
and Item_Code in ( `toString(shQuote(Item_Code, 'sh'))` )")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.