2016-08-24 6 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の試行または受け入れられた回答のいずれも、真のパラメータ化されたSQLクエリーではない。 @Benjaminはより良い試みですが、他のものは単純に動的SQL文字列を連結しています。 – Parfait

答えて

0

:私たちは交互に文字列補間のためのgsubfnパッケージからfn$を使用することができます

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

:OPと将来の読者に

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を見るとよいでしょう。 sqlExecuteは(リストは、データフレームに強制変換されますdata引数の各行に対してクエリを実行しますので、適切にクエリをパラメータ化する

、あなたが

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 
) 

を行うことがありますが、これは、しかし、大きな欠点を持っています)。 itemベクトルに何百もの要素がある場合、SQLインスタンスで何百ものクエリを実行しますが、これは特に効率的ではありません。

これを実行するあまり明白な方法では、ストアドプロシージャを作成してクエリを構築します。

SQLであなたのストアドプロシージャは、あなたが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 
) 

、この方法で動作します

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 

のようになります。 itemで渡されたフォーマットされていない文字列の問題の影響を受けやすくなりますが、表示される最初の方法では何百ものクエリを実行するよりも高速になる可能性があります。質問のように文字列操作でこれを行うには