Добавление значения в существующую таблицу базы данных в RSQLite

Я новичок в RSQLite. У меня есть входной документ в текстовом формате, в котором значения указаны отдельно с помощью «|» Я создал таблицу с необходимыми переменными (фиктивный код следующим образом)

db<-dbconnect(SQLite(),dbname="test.sqlite")

dbSendQuery(conn=db,
"CREATE TABLE TABLE1(
MARKS INTEGER,
ROLLNUM INTEGER
NAME CHAR(25)
DATED DATE)"
)

Однако я поражен тем, как импортировать значения в созданную таблицу. Я не могу использовать команду INSERT INTO Values, поскольку в исходном файле данных тысячи строк и более 20 столбцов, и невозможно вручную ввести каждую точку данных.

Может ли кто-нибудь предложить альтернативный эффективный способ сделать это?


person Sanju    schedule 20.09.2017    source источник
comment
Связано: stackoverflow.com/q/25194568/946850.   -  person krlmlr    schedule 21.09.2017


Ответы (3)


Вы используете язык сценариев. Дело в том, что буквально избежать ручного ввода каждой точки данных. Извини.

У вас есть два маршрута:

1: вы исправили загруженное соединение с базой данных и создали пустую таблицу в своей базе данных SQLite. Ницца!

Чтобы загрузить данные в таблицу, загрузите текстовый файл в R, используя, например. df <- read.table('textfile.txt', sep='|') (измените аргументы, чтобы они соответствовали вашему текстовому файлу).

Чтобы иметь «динамический» оператор INSERT, вы можете использовать заполнители. RSQLite позволяет использовать как именованный, так и позиционированный заполнитель. Чтобы вставить одну строку, вы можете сделать:

dbSendQuery(db, 'INSERT INTO table1 (MARKS, ROLLNUM, NAME) VALUES (?, ?, ?);', list(1, 16, 'Big fellow'))

Понимаете? Первый ? получил значение 1, второй ? получил значение 16, а последний ? получил строку Big fellow. Также обратите внимание, что вы не заключаете заполнители для текста в кавычки (' или ")!

Теперь у вас есть тысячи строк. Или просто больше одного. В любом случае, вы можете отправить свой фрейм данных. dbSendQuery предъявляет некоторые требования. 1) Каждый вектор имеет одинаковое количество записей (не проблема при предоставлении data.frame). И 2) Вы можете только отправить столько векторов, сколько у вас есть заполнителей.

Я предполагаю, что ваш фрейм данных df содержит столбцы mark, roll и name, соответствующие столбцам. Затем вы можете запустить:

dbSendQuery(db, 'INSERT INTO table1 (MARKS, ROLLNUM, NAME) VALUES (:mark, :roll, :name);', df)

Это выполнит оператор INSERT для каждой строки в df!

СОВЕТ! Поскольку инструкция INSERT выполняется для каждой строки, вставка тысяч строк может занять много времени, поскольку после каждой вставки данные записываются в файл, а индексы обновляются. . Вставьте, заключите его в транзакцию:

dbBegin(db)
res <- dbSendQuery(db, 'INSERT ...;', df)
dbClearResult(res)
dbCommit(db)

и SQLite сохранит данные в файл журнала и сохранит результат только при выполнении команды dbCommit(db). Попробуйте оба метода и сравните скорость!


2: А, да. Второй способ. Это можно сделать полностью в SQLite. С помощью командной утилиты SQLite (sqlite3 из вашей командной строки, а не R) вы можете прикрепить текстовый файл в виде таблицы и просто выполнить команду INSERT INTO ... SELECT ... ;. В качестве альтернативы, прочитайте текстовый файл в sqlite3 во временную таблицу и запустите INSERT INTO ... SELECT ... ;.


Полезный сайт для запоминания: http://www.sqlite.com/lang.html

person MrGumble    schedule 20.09.2017
comment
Это не отвечает на вопрос. - person Tim Biegeleisen; 20.09.2017
comment
Как это не отвечает на вопрос? - person MrGumble; 20.09.2017
comment
Can someone suggest an alternative efficient way to do so? ... в мире баз данных генерация сценария INSERT с тысячами операторов или более не будет считаться эффективной. В любой крупной СУБД ваш ответ не будет предпочтительным ни с точки зрения производительности, ни с точки зрения точности. - person Tim Biegeleisen; 20.09.2017
comment
И мой ответ — это эффективный способ сделать это в рамках RSQLite, о котором он просит. - person MrGumble; 20.09.2017

Я не думаю, что есть хороший способ сделать большое количество вставок непосредственно из R. SQLite действительно имеет функцию массовой вставки, но пакет RSQLite, похоже, не предоставляет ее.

Из командной строки вы можете попробовать следующее:

.separator |
.import your_file.csv your_table

где your_file.csv — файл CSV (или файл с разделителями вертикальной черты), содержащий ваши данные, а your_table — целевая таблица.

Дополнительные сведения см. в документации в разделе "Импорт CSV".

person Tim Biegeleisen    schedule 20.09.2017
comment
RSQLite поддерживает вставку (или выбор!) Через, например. кадр данных или вектор, см. мой ответ. И спасибо за ваш ответ, так как это был мой второй подход, но мне было лень писать полностью. - person MrGumble; 20.09.2017
comment
@MrGumble Нет, похоже, он не поддерживает массовую вставку, и весь смысл вопроса ОП заключался в том, чтобы избежать грязного и неэффективного сценария для создания операторов вставки. - person Tim Biegeleisen; 20.09.2017
comment
Что ты имеешь в виду; какая часть моего ответа показывает, что RSQLite не поддерживает массовые вставки? Он буквально действительно поддерживает массовые вставки, см. мой ответ. RSQLite поддерживает как именованные, так и неименованные заполнители в операторах INSERT и SELECT, позволяя пользователю указывать векторы значений для вставки в заполнители. - person MrGumble; 20.09.2017
comment
@TimBiegeleisen: проверьте новый dbBind(), особенно примеры там. Должно быть достаточно быстро для многих приложений. - person krlmlr; 21.09.2017

Немного поздно для вечеринки, но DBI предоставляет dbAppendTable(), который запишет содержимое кадра данных в таблицу SQL. Имена столбцов в кадре данных должны совпадать с именами полей в базе данных. В вашем примере следующий код вставит содержимое моего случайного фрейма данных в вашу вновь созданную таблицу.

library(DBI)

db<-dbConnect(RSQLite::SQLite(),dbname=":memory")

dbExecute(db,
          "CREATE TABLE TABLE1(
             MARKS INTEGER,
             ROLLNUM INTEGER,
             NAME TEXT
           )"
)

df <- data.frame(MARKS = sample(1:100, 10), 
                 ROLLNUM = sample(1:100, 10), 
                 NAME = stringi::stri_rand_strings(10, 10))

dbAppendTable(db, "TABLE1", df)
person blongworth    schedule 09.06.2021