Как сохранить R DataFrame в файл в формате резервной копии MS SQL? - PullRequest
0 голосов
/ 19 июня 2020

Мне нужно передать на внешний сервер MS SQL большой объем данных, рассчитанных в R.

  • Прямой доступ к БД невозможен, поэтому это должен быть промежуточный файл экспорта.
  • Формат Excel нельзя использовать из-за того, что количество строк данных превышает емкость Excel.
  • CSV подойдет, но в самих данных есть много препятствий, таких как точки с запятой, используемые в именах, специальных символах, незакрытые цитаты (нечетное число ") и т. д.

Я ищу универсальный метод переноса данных из R в базу данных MS SQL, независимо от содержания данных. Если бы я мог сохранить DataFrame как базу данных, содержащую одну таблицу, в файл формата резервной копии MS SQL, который удовлетворит потребности. 1013 *

1 Ответ

1 голос
/ 19 июня 2020

Я предполагаю, что вы надеетесь массово вставить данные, используя bcp или sqlcmd. Хотя ни один из них не справляется с запятыми, встроенными запятыми и встроенными кавычками, вы можете обойти это, используя другой разделитель полей (т.е. , а не , содержащийся в данных).

Настройка:

evil_data <- data.frame(
  id = 1:2,
  chr = c('evil"string ,;\n\'', '",";:|"'),
  stringsAsFactors = FALSE
)
# con <- DBI::dbConnect(...)
DBI::dbExecute(con, "create table r2test (id INT, chr nvarchar(64))")
# [1] 0
DBI::dbWriteTable(con, "r2test", evil_data, create = FALSE, append = TRUE)
DBI::dbGetQuery(con, "select * from r2test")
#   id               chr
# 1  1 evil"string ,;\n'
# 2  2           ",";:|"

Сначала я буду использовать \U001 в качестве разделителя полей и \U002 в качестве разделителя строк. Эти два должны быть «достаточно хорошими», но если у вас есть непечатаемые символы в ваших данных, вы можете либо изменить свои разделители на другие значения, либо поискать параметры кодирования для данных (например, base64, хотя это может быть необходимо хранится таким образом).

write.table(evil_data, "evil_data.tab", sep = "\U001", eol = "\U002", quote = FALSE)
# or data.table::fwrite or readr::write_delim

Поскольку я использую bcp, он может использовать «файл формата» для обозначения разделителей и того, какие столбцы в источнике соответствуют столбцам в базе данных. См. Ссылки о том, как создать этот файл, но для этого примера я буду использовать:

fmt <- c("12.0", "2",
         "1       SQLCHAR             0       0       \"\001\"    1     id                                                               \"\"                          ", 
         "2       SQLCHAR             0       0       \"\002\"    2     chr                                                              SQL_Latin1_General_CP1_CI_AS")
writeLines(fmt, "evil_data.fmt")

Отсюда, предполагая, что bcp находится в вашем PATH (вам понадобится абсолютный путь для bcp в противном случае), запустите это в терминале (я использую git - bash на windows, но это должно быть таким же в других). Во второй строке указано соединение c с my с базой данных, вам нужно пропустить или изменить все это для вашего собственного подключения. Первая строка: ваш материал

$ bcp [db_owner].[r2test] in evil_data.tab -F2 -f evil_data.fmt -r '\002' \
  -S '127.0.0.1,21433' -U 'myusername' -d 'mydatabase' -P ***MYPASS***

Starting copy...

2 rows copied.
Network packet size (bytes): 4096
Clock Time (ms.) Total     : 235    Average : (8.51 rows per sec.)

Доказательство того, что это сработало:

DBI::dbGetQuery(con, "select * from r2test")
#   id                      chr
# 1  1        evil"string ,;\n'
# 2  2                  ",";:|"
# 3  1 1\001evil"string ,;\r\n'
# 4  2             2\001",";:|"

Ссылки:

...