2009-09-09 22 views
7

È possibile eseguire un inserimento di massa in un MS-SQL Server (2000, 2005, 2008) utilizzando il pacchetto RODBC?Inserimento bulk MS-SQL con RODBC

So che posso farlo utilizzando freebcp, ma sono curioso se il pacchetto RODBC implementa questa parte dell'API di Microsoft SQL e, in caso contrario, quanto sarebbe difficile implementarlo.

risposta

2

Probabilmente stai cercando ?sqlSave che utilizza una query parametrizzata INSERT INTO (che si svolge in un'unica operazione) quando imposti Fast=True.

+3

Nah, sqlSave farà più INSERTI. Voglio un BULK INSERT che è una singola transazione. – ephpostfacto

+0

fa fast = true non lo fa come una singola transazione? – Tyler

+1

da rodbc docs: "logico, se falso, scrivere i dati una riga alla volta, se è vero, utilizzare una query INSERT INTO o UPDATE parametrizzata per scrivere tutti i dati in un'unica operazione." .. tuttavia non sembra fare qualche differenza (quando si scrive a Netezza nel mio caso) – Joe

2

Ora è possibile utilizzare dbBulkCopy dal nuovo rsqlserver pacchetto:

Un tipico scenario:

  1. Si crea una matrice
  2. si salva come file CSV
  3. vi chiamo dbBulkCopy a leggere il file e inserirlo utilizzando lo strumento interno bcp del server MS Sql.

Questo supporre che la tabella sia già stato creato nella base di dati:

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

per quale motivo rsqlserver non è su cran? – jangorecki

+1

@MusX perché è in fase di sviluppo (specialmente parte di documentazione e test) e usa il pacchetto 'rClr' che non è anche su CRAN. Ma sei incoraggiato ad usarlo da GITHUB e sarai felice di qualsiasi feedback. – agstudy

1

Da tutto quello che riesco a trovare, non esiste una soluzione per inserimento di massa a MySQL e niente che funziona con SSIS che è il motivo Microsoft include l'analisi in-database con SQL Server 2016 dopo l'acquisto di Revolution R Analytics.

Ho provato a commentare la risposta precedente ma non ho la reputazione di farlo.

Il pacchetto rsqlserver deve essere eseguito con rClr e nessuno di questi pacchetti è ben educato, soprattutto perché le funzioni INSER dello rsqlserver hanno una cattiva gestione dei tipi di dati. Quindi, se lo usi, non avrai idea di cosa stai guardando nella tabella SQL in quanto molte delle informazioni nel tuo data.frame saranno state trasformate.

Considerando il pacchetto RODBC è stato intorno per 15 anni, sono abbastanza deluso dal fatto che nessuno ha creato una funzione di inserimento di massa ...

+1

importante punto su rsqlserver, ma per molti di noi non abbiamo bisogno di 'guardare' i dati (da un punto di vista R). Se è stato modellato, modellato ed elaborato in R, abbiamo solo bisogno del risultato nel database e non importa quale R trasforma il tipo nel database (purché siano ragionevoli e possano essere letti da altri sistemi) – Joe

1

nostro pacchetto n2khelper possibile utilizzare bcp (bulkcopy) quando è disponibile. Quando non disponibile, torna a più istruzioni INSERT.

È possibile trovare il pacchetto su https://github.com/INBO-Natura2000/n2khelper

Installarlo con devtools::install_git("INBO-Natura2000/n2khelper") e cercare la funzione odbc_insert().

4

controlla i nuovi pacchetti odbc e DBI. DBI::dbWriteTable scrive circa 20.000 record al secondo ... Molto più veloce degli inserimenti di riga da RODBC::sqlSave()

-1

Stiamo utilizzando questa funzione per inserire tabelle di massa. Utilizza il pacchetto RODBC e la sua connessione.

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 vediamo come questo sta facendo un caricamento collettivo. Non sta solo creando una query 'INSERT INTO ... 'e inviandola da' sqlQuery'? Quindi lo manderà ancora una riga alla volta, anche se R le sta elaborando come chunk.s –

+0

@PeterEllis Ovviamente sta creando un'istruzione INSERT INTO ma ci sono 1000 valori di riga (chunksize) in quell'istruzione. Quindi funziona in ore (dati)/tempi di chunksize. Diciamo che abbiamo hava un dato contiene 50k righe. Invia 50 query anziché 50000 query al database. Quindi c'è un significativo aumento della velocità. – Sab

0

Utilizzando RODBC, l'inserto più veloce siamo stati in grado di creare (260 milioni di riga di inserimento) è simile al seguente (in R pseudo codice):

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;") 

se si sta eseguendo questo tra i server, è necessaria un'unità di rete su cui il server R può scrivere (ad esempio, un server con autorizzazioni per la scrittura nel DB utilizza Rscript per la produzione del codice) e da cui SQL Server può leggere.