2009-09-09 17 views
7

Czy można przeprowadzić zbiorczą wstawkę do serwera MS-SQL (2000, 2005, 2008) przy użyciu pakietu RODBC?Wstawka zbiorcza MS-SQL z RODBC

Wiem, że mogę to zrobić za pomocą freebcp, ale jestem ciekawy, czy pakiet RODBC implementuje tę część Microsoft SQL API, a jeśli nie, jak trudno byłoby go wdrożyć.

Odpowiedz

2

Prawdopodobnie szukasz ?sqlSave, która używa sparafizowanej zapytania INSERT INTO (odbywa się w jednej operacji) po ustawieniu Fast=True.

+3

Nah, sqlSave wykona wiele WKŁADÓW. Chcę BULK INSERT, który jest pojedynczą transakcją. – ephpostfacto

+0

czy fast = true nie robi tego jako pojedyncza transakcja? – Tyler

+1

from the rodbc docs: "logiczne Jeśli false, zapisuj dane w wierszu na raz. Jeśli jest to prawda, użyj sparametryzowanego zapytania INSERT INTO lub UPDATE, aby zapisać wszystkie dane w jednej operacji." .. jednak nie wydaje się zrobić jakąkolwiek różnicę (przy pisaniu do Netezzy w moim przypadku) – Joe

2

Teraz można użyć dbBulkCopy z nowej rsqlserver opakowania:

Typowy scenariusz:

  1. utworzyć macierz
  2. zapisać go w postaci pliku csv
  3. można nazwać dbBulkCopy do wczytaj plik i wstaw go wewnętrznie przy użyciu narzędzia MS Sql server bcp.

to zakładamy, że tabela jest już utworzony w bazie danych:

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

jakikolwiek powód, dla którego rsqlserver nie znajduje się na cranu? – jangorecki

+1

@MusX, ponieważ jest w fazie rozwoju (szczególnie dokumentacja i część testowa) i używa pakietu 'rclr', który nie jest również w CRAN. Zachęcamy jednak do korzystania z niego od GITHUB i będziemy zadowoleni z każdej opinii. – agstudy

1

Od wszystkiego mogę znaleźć, nie ma rozwiązania dla insertu luzem do MySQL i nic, który współpracuje z SSIS, dlatego Firma Microsoft uwzględnia analitykę w bazie danych w programie SQL Server 2016 po zakupie oprogramowania Revolution R Analytics.

Próbowałem skomentować poprzednią odpowiedź, ale nie mam reputacji, aby to zrobić.

Pakiet rsqlserver musi działać z rClr i żaden z tych pakietów nie jest dobrze zachowany, zwłaszcza, że ​​funkcje INSERT rsqlserver mają słabą obsługę typów danych. Więc jeśli go użyjesz, nie będziesz miał pojęcia, co patrzysz w tabeli SQL, ponieważ wiele informacji w twoim pliku data.frame zostanie przekształconych.

Biorąc pod uwagę pakiet RODBC zostało około 15 lat, jestem bardzo rozczarowany, że nikt nie stworzył luzem funkcji wstawiania ...

+1

ważny punkt na rsqlserver, ale dla wielu z nas nie musimy "patrzeć" na dane (z punktu widzenia R). Jeśli został wymodelowany i ukształtowany i przetworzony w R, po prostu potrzebujemy wyniku z powrotem w bazie danych i nie ma znaczenia, co R przekształca typ w bazie danych (o ile są one rozsądne i mogą być odczytywane przez inne systemy) – Joe

1

Nasz pakiet n2khelper mogą korzystać bcp (bulkcopy), gdy jest ona dostępna. Kiedy nie jest dostępny, wraca do wielu instrukcji INSERT.

można znaleźć pakiet na https://github.com/INBO-Natura2000/n2khelper

zainstalować go z devtools::install_git("INBO-Natura2000/n2khelper") i poszukać funkcji odbc_insert().

4

Sprawdź nowe pakiety odbc i DBI. DBI::dbWriteTable zapisuje około 20 000 rekordów na sekundę ... Znacznie szybciej niż wstawki wierszy od RODBC::sqlSave()

-1

Używamy tej funkcji do wstawiania tabel zbiorczych. Używa pakietu RODBC i jego połączenia.

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

zobacz, jak to jest przesyłanie zbiorcze. Czy nie jest to po prostu tworzenie zapytania 'INSERT INTO ...' i wysyłanie go przez 'sqlQuery'? Więc nadal będzie wysyłał jeden wiersz na raz, nawet jeśli R przetwarza je jako fragment. –

+0

@PeterEllis Oczywiście tworzy on instrukcje INSERT INTO, ale w tym zestawieniu występuje 1000 (części wielkości) wierszy. Tak więc działa to w czasie nrow (data)/chunksize. Załóżmy, że dane w hava zawierają 50 tys. Wierszy. Wysyła 50 zapytań zamiast 50000 zapytań do bazy danych. Tak więc istnieje znaczny wzrost prędkości. – Sab

0

Korzystanie RODBC, najszybszy wkładka byliśmy w stanie stworzyć rząd (260 mln wkładkę) wygląda następująco (w R pseudo kod):

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

Jeśli używasz tego pomiędzy serwerami potrzebny jest dysk sieciowy, do którego serwer R może pisać (np. jeden serwer z uprawnieniami do zapisu do bazy danych używa Rscript do produkcji kodu) i SQL Server może czytać.