2016-08-24 71 views
0

我正試圖通過Vertica DB中的RODBC包提取數據。我目前有一個SQL查詢,如下所示。帶有IN子句的R中的參數化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個不同的項目)。

如果它可以從外部矢量或文件傳遞,有沒有辦法?

+2

到OP和未來的讀者 - 請注意OP的嘗試或接受的答案都不是真正的參數化SQL查詢。 @Benjamin是一個更好的嘗試,而其他人只是簡單地連接一個動態SQL字符串。 – Parfait

回答

0

要使用字符串操作做到這一點作爲一個問題:

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'))) 

我們可以交替使用fn$從gsubfn包串插:

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'))`)") 
2

什麼是SQL注入而不是參數化查詢。您可能需要查看RODBCext包裝及其vignette

要正確參數化查詢,你可以做

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傳遞格式不正確的字符串的問題,但它可能比在我顯示的第一種方法中運行數百個查詢更快。