簡體   English   中英

R中帶有IN子句的參數化SQL查詢

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM