2016-06-07 87 views
1

这个问题是对How to quickly export data from R to SQL Server这个问题的延伸。目前我使用下面的代码:如何在不从RODBC包创建文本文件的情况下批量在SQLServer中插入数据?

# DB Handle for config file # 
    dbhandle <- odbcDriverConnect() 

# save the data in the table finally 
    sqlSave(dbhandle, bp, "FACT_OP", append=TRUE, rownames=FALSE, verbose = verbose, fast = TRUE) 
# varTypes <- c(Date="datetime", QueryDate = "datetime") 
# sqlSave(dbhandle, bp, "FACT_OP", rownames=FALSE,verbose = TRUE, fast = TRUE, varTypes=varTypes) 

# DB handle close 
    odbcClose(dbhandle) 

我已经试过这种方法也,这是工作精美,我已经获得了显著速度为好。

toSQL = data.frame(...); 
write.table(toSQL,"C:\\export\\filename.txt",quote=FALSE,sep=",",row.names=FALSE,col.names=FALSE,append=FALSE); 
sqlQuery(channel,"BULK 
      INSERT Yada.dbo.yada 
      FROM '\\\\<server-that-SQL-server-can-see>\\export\\filename.txt' 
      WITH 
      (
      FIELDTERMINATOR = ',', 
      ROWTERMINATOR = '\\n' 
      )"); 

但我的问题是,我不能让我的数据在休息的交易之间(将数据写入一个文件是不是因为数据安全的一个选项),所以我一直在寻找解决办法,如果我可以直接批量插入从内存或缓存数据。谢谢您的帮助。

+0

我不认为在这里问什么是清楚的。您可以从内存中插入,但速度会更慢。 – Bulat

+0

对不起,以前并不清楚,我已经更新了这个问题。这就是我现在正在做的sqlSave,它比较慢,所以我正在寻找其他选项。 – nsDataSci

+0

因此,您希望使用相同速度的内存解决方案?我不认为它存在,否则大多数DB提供的批量导入功能都没有意义。 – Bulat

回答

-1

如何使用DBI::dbWriteTable()函数?下面 示例(我连接我的R代码里面来的MS SQL ExpressAWS RDS实例):

library(DBI) 
library(RJDBC) 
library(tidyverse) 

# Specify where you driver lives 
drv <- JDBC(
    "com.microsoft.sqlserver.jdbc.SQLServerDriver", 
    "c:/R/SQL/sqljdbc42.jar") 

# Connect to AWS RDS instance 
conn <- drv %>% 
    dbConnect(
    host = "jdbc:sqlserver://xxx.ccgqenhjdi18.ap-southeast-2.rds.amazonaws.com", 
    user = "xxx", 
    password = "********", 
    port = 1433, 
    dbname= "qlik") 

if(0) { # check what the conn object has access to 
    queryResults <- conn %>% 
    dbGetQuery("select * from information_schema.tables") 
} 

# Create test data 
example_data <- data.frame(animal=c("dog", "cat", "sea cucumber", "sea urchin"), 
          feel=c("furry", "furry", "squishy", "spiny"), 
          weight=c(45, 8, 1.1, 0.8)) 
# Works in 20ms in my case 
system.time(
    conn %>% dbWriteTable(
    "qlik.export.test", 
    example_data 
) 
) 

# Let us see if we see the exported results 
conn %>% dbGetQuery("select * FROM qlik.export.test") 

# Let's clean the mess and force-close connection at the end of the process 
conn %>% dbDisconnect() 

它的工作原理相当快的传输数据量小,如果你想data.frame似乎相当优雅 - >SQL table解决方案。

享受!

0

好问题 - 在无论何种原因无法设置BULK INSERT权限的情况下也很有用。

我把这个可怜的人的解决方案放在一起,当我有足够的数据时,sqlSave太慢了,但还不足以证明设置BULK INSERT是正确的,因此它不需要将任何数据写入文件。 sqlSave和参数化查询对于插入数据非常缓慢的主要原因是每个行都插入了新的INSERT语句。作为R写入INSERT声明手动绕过这在我下面的例子:写出来与值将在一次接受长达1000行

library(RODBC) 
channel <- ... 
dataTable <- ...relevant data... 
numberOfThousands <- floor(nrow(dataTable)/1000) 
extra <- nrow(dataTable)%%1000 

thousandInsertQuery <- function(channel,dat,range){ 
    sqlQuery(channel,paste0("INSERT INTO Database.dbo.Responses (IDNum,State,Answer) 
            VALUES " 
          ,paste0(
          sapply(range,function(k) { 
           paste0("(",dat$IDNum[k],",'", 
            dat$State[k],"','", 
            gsub("'","''",dat$Answer[k],fixed=TRUE),"')") 
          })           
          ,collapse=","))) 
} 

if(numberOfThousands) 
    for(n in 1:numberOfThousands) 
    { 
    thousandInsertQuery(channel,(1000*(n-1)+1):(1000*n),dataTable) 
    } 
if(extra) 
    thousandInsertQuery(channel,(1000*numberOfThousands+1):(1000*numberOfThousands+extra)) 

SQL的INSERT语句,所以这段代码将其分解成块(更有效地比一次一行)。

thousandInsertQuery函数显然必须自定义以处理数据框所具有的任何列 - 还要注意字符/因子列周围有单引号,并且要处理可能位于字符列中的任何单引号。除此之外,没有针对SQL注入攻击的保护措施。

相关问题