Я предполагаю, что вы надеетесь массово вставить данные, используя 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",";:|"
Ссылки: