2009-09-09 24 views
7

¿Es posible realizar una inserción masiva en un servidor MS-SQL (2000, 2005, 2008) utilizando el paquete RODBC?MS-SQL Bulk Insert con RODBC

Sé que puedo hacer esto usando freebcp, pero tengo curiosidad por saber si el paquete RODBC implementa esta parte de la API de Microsoft SQL y, de no ser así, qué tan difícil sería implementarlo.

Respuesta

2

Probablemente esté buscando ?sqlSave que utiliza una consulta parametrizada INSERT INTO (que tiene lugar en una sola operación) cuando establece Fast=True.

+3

Nah, sqlSave hará múltiples inserciones. Quiero un BULK INSERT, que es una transacción única. – ephpostfacto

+0

lo hace rápido = cierto no hacerlo como una sola transacción? – Tyler

+1

de los documentos rodbc: "lógico. Si es falso, escriba los datos de una fila a la vez. Si es verdadero, utilice una consulta parametrizada INSERT INTO o UPDATE para escribir todos los datos en una sola operación." ... sin embargo, no parece hacer alguna diferencia (al escribir a Netezza en mi caso) – Joe

2

Ahora puede utilizar dbBulkCopy de la nueva rsqlserver paquete:

Un escenario típico:

  1. Se crea una matriz
  2. se guarda como un archivo csv
  3. se llama a dbBulkCopy a lea fil e insértela utilizando internamente la herramienta bcp del servidor MS Sql.

Esto asume que la tabla ya se ha creado en la base de datos:

dat <- matrix(round(rnorm(nrow*ncol),nrow,ncol) 
id.file = "temp_file.csv"      
write.csv(dat,file=id.file,row.names=FALSE) 
dbBulkCopy(conn,'NEW_BP_TABLE',value=id.file) 
+0

¿por qué rsqlserver no está en Cran? – jangorecki

+1

@MusX porque está en desarrollo (especialmente la parte de documentación y pruebas) y utiliza el paquete 'rClr' que tampoco está en CRAN. Pero se lo alienta a usarlo de GITHUB y estará contento con cualquier comentario. – agstudy

1

De todo lo que puedo encontrar, no hay solución para la inserción masiva a MySQL y nada que funciona con SSIS razón por la cual Microsoft incluye análisis en la base de datos con SQL Server 2016 después de comprar Revolution R Analytics.

Traté de comentar sobre la respuesta anterior, pero no tengo la reputación de hacerlo.

El paquete rsqlserver debe ejecutarse con rClr y ninguno de esos paquetes se comporta bien, especialmente porque las funciones INSERT de rsqlserver tienen un mal manejo de tipo de datos. Entonces, si lo usa, no tendrá idea de lo que está viendo en la tabla SQL ya que gran parte de la información en su data.frame se habrá transformado.

Teniendo en cuenta el paquete RODBC ha sido de alrededor de 15 años, estoy bastante decepcionado de que nadie ha creado una función de inserción masiva ...

+1

punto importante en rsqlserver, pero para muchos de nosotros no necesitamos 'mirar' los datos (desde el punto de vista R). Si ha sido modelado, modelado y procesado en R, solo necesitamos el resultado en la base de datos y no importa a qué R transforma el tipo en la base de datos (siempre que sean razonables y puedan ser leídos por otros sistemas) – Joe

1

Nuestro paquete n2khelper puede utilizar bcp (bulkcopy) cuando está disponible. Cuando no está disponible, regresa a múltiples instrucciones INSERT.

puede encontrar el paquete en https://github.com/INBO-Natura2000/n2khelper

instalarlo con devtools::install_git("INBO-Natura2000/n2khelper") y buscar la función odbc_insert().

4

revisa los nuevos paquetes odbc y DBI. DBI::dbWriteTable escribe alrededor de 20,000 registros por segundo ... Mucho más rápido que las Inserciones de fila de RODBC::sqlSave()

-1

Estamos utilizando esta función para insertar tablas voluminosas. Utiliza el paquete RODBC y su conexión.

dbhandle <- odbcDriverConnect('driver={SQL Server};server=server...') 

sqlInsertBulk <- function(data, table, dbhandle,chunksize = 1000) 
{ 
    stopifnot(chunksize <= 1000) 
    nrow_initial<-sqlQuery(dbhandle,paste("SELECT COUNT (1) FROM ",table)) 
    #If data includes Inf value, stop function. 
    numericCols <- names(data)[sapply(data, is.numeric)] 
    if (length(numericCols != 0)) { 
    if(sum(unlist(data[,lapply(.SD, function(x) any(x == Inf)),.SDcols = numericCols]),na.rm=T)>0){ 
     stop("Data includes Inf value.") 
    } 
    } 
    chunknumber <- ceiling(nrow(data)/chunksize) 

    qstart <- paste("INSERT INTO ", table ," (",paste(colnames(data),collapse = ", "), ") VALUES") 

    for(chunki in 1:chunknumber) 
    { 
    chunkstart <- 1 + chunksize * (chunki - 1) 
    chunkend <- min(nrow(data), chunki * chunksize) 
    chunkdata <- data[chunkstart:chunkend] 
    valuestring <- vector(mode="character", length=chunkend - chunkstart + 1) 
    for(i in 1:nrow(chunkdata)){ 
     valuestring[i] <- paste("(", paste(sapply(chunkdata[i], function(input){ 
     if(!class(input) %in% c("numeric", "integer")) { 
      input<-paste0("'", input, "'") 
     } 
     if(is.na(input)) 
     { 
      input<-"NULL" 
     } 
     return (input) 
     }), collapse=", "), ")") 
    } 

    qend <- paste(valuestring, collapse = ", ") 
    q <- paste(qstart, qend) 
    print(paste("Chunk", chunki, "is in process.")) 
    sqlQuery(dbhandle,q) 
    print(paste("Chunk", chunki, "is uploaded.")) 
    } 

    nrow_final <- sqlQuery(dbhandle,paste("SELECT COUNT (1) FROM ",table)) 
    if(nrow_final-nrow_initial==nrow(data)) { 
    print(paste("All ",nrow(data)," data is uploaded.")) 
    } else { 
    print(paste0("Warning!!! Only ",nrow_final-nrow_initial, " out of ",nrow(data), " are uploded.")) 
    } 
} 
+0

I don No veo cómo esto está haciendo una carga masiva. ¿No es solo crear una consulta 'INSERT INTO ...' y enviarla por 'sqlQuery'? Por lo tanto, seguirá enviando una fila a la vez, aunque R los esté procesando como fragmento. –

+0

@PeterEllis Por supuesto, está creando una instrucción INSERT INTO, pero hay valores de fila de 1000 (tamaño de fragmento) en esa declaración. Por lo tanto, funciona nrow (data)/chunksize veces. Digamos que tenemos un dato que contiene 50k filas. Envía 50 consultas en lugar de consultas 50000 a la base de datos. Entonces, hay un aumento significativo en la velocidad. – Sab

0

Usando RODBC, la inserción más rápida que hemos sido capaces de crear (260 millones fila de inserción) se parece a la siguiente (en pseudo código R):

ourDataFrame <- sqlQuery(OurConnection, "SELECT myDataThing1, myDataThing2 
             FROM myData") 
ourDF <- doStuff(ourDataFrame) 
write.csv(ourDF,ourFile) 
sqlQuery(OurConnection, "CREATE TABLE myTable (la [La], laLa [LaLa]); 
         BULK INSERT myTable FROM 'ourFile' 
           WITH YOURPARAMS=yourParams;") 

si se está ejecutando este entre servidores, necesita una unidad de red en la que el servidor R pueda escribir (por ejemplo, un servidor con permisos para escribir en la base de datos usa Rscript para producir el código) y SQL Server puede leer.