Как мне выгрузить данные и только данные, а не схему некоторых таблиц SQLite3 базы данных (не всех таблиц)? Дамп должен быть в формате SQL, так как он должен быть легко повторно введен в базу данных позже и должен выполняться из командной строки. Что-то вроде
sqlite3 db .dump
но без сброса схемы и выбора таблиц для сброса.
Я хочу сделать дамп в формате SQL, чтобы можно было легко его восстановить. Я добавил эту информацию к основному вопросу.


Вы можете сделать выбор в таблицах, вставив запятые после каждого поля для создания CSV, или использовать инструмент с графическим интерфейсом, чтобы вернуть все данные и сохранить их в CSV.
Я намеревался создать файл SQL, который можно было бы легко повторно добавить в БД.
Лучшим способом было бы взять код, который будет делать дамп sqlite3 db, за исключением частей схемы.
Пример псевдокода:
SELECT 'INSERT INTO ' || tableName || ' VALUES( ' ||
{for each value} ' quote(' || value || ')' (+ commas until final)
|| ')' FROM 'tableName' ORDER BY rowid DESC
Смотрите: src/shell.c:838 (для sqlite-3.5.9) для фактического кода
Вы можете даже просто взять эту оболочку, закомментировать части схемы и использовать их.
Вы не говорите, что хотите сделать с выгруженным файлом.
Я бы использовал следующее, чтобы получить файл CSV, который я могу импортировать почти во все
.mode csv
-- use '.separator SOME_STRING' for something other than a comma.
.headers on
.out file.csv
select * from MyTable;
Если вы хотите повторно вставить в другую базу данных SQLite, тогда:
.mode insert <target_table_name>
.out file.sql
select * from MyTable;
Есть ли способ сделать это программно с помощью операторов SQL? Я вижу, как это сделать с помощью интерпретатора, но что, если я захочу написать сценарий?
Вы можете поместить свои операторы в файл (например, sample.txt), а затем вызвать его, используя: sqlite3 db.sq3 <sample.txt
«Или используйте команду .once вместо .output, и вывод будет перенаправлен только для одной следующей команды перед возвратом в консоль. Используйте .output без аргументов, чтобы снова начать запись в стандартный вывод.» Документы SQLite
Не лучший способ, но, по крайней мере, не требует внешних инструментов (кроме grep, который в любом случае является стандартным для ящиков * nix)
sqlite3 database.db3 .dump | grep '^INSERT INTO "tablename"'
но вам нужно выполнить эту команду для каждой таблицы, которую вы ищете.
Обратите внимание, что это не включает схему.
Я использовал sqlite3 Database.s3db .dump
Это сломается, если эти вставки содержат символы новой строки в значениях. Лучше используйте grep -v '^CREATE', как предлагается в одном из других ответов.
использование grep -v '^CREATE; приведет к прерыванию, если в операторах CREATE есть разрывы строк (что иногда бывает). Лучше всего, ИМО, вообще не удалять операторы CREATE автоматически, а вручную отредактировать их. Просто используйте любой текстовый редактор, который вам нужен, найдите CREATE и вручную удалите эти операторы. Пока база данных не огромна (и, поскольку вы используете sqlite, я предполагаю, что это примечание), это довольно просто.
но grep создания также возьмет создание из представлений. как я могу это удалить?
Вы можете указать один или несколько аргументов таблицы для специальной команды .dump, например, sqlite3 db ".dump 'table1' 'table2'".
когда я добавляю несколько имен таблиц, как вы упомянули, это дает мне следующий результат: Использование: .dump? - preserve-rowids? ? КАК ОБРАЗЕЦ?
@mwm Наблюдаю ту же проблему в sqlite3 3.31.1 (2020/01/27). журнал изменений ничего об этом не говорит. (Кстати, --preserve-rowids действительно работает, но совсем не документирован.)
Вы можете сделать это, получив разницу команд .schema и .dump. например, с помощью grep:
sqlite3 some.db .schema > schema.sql
sqlite3 some.db .dump > dump.sql
grep -vx -f schema.sql dump.sql > data.sql
Файл data.sql будет содержать только данные без схемы, примерно так:
BEGIN TRANSACTION;
INSERT INTO "table1" VALUES ...;
...
INSERT INTO "table2" VALUES ...;
...
COMMIT;
Я надеюсь, это поможет вам.
@anurageldorado это простой sql. просто запустите sqlite3 some.db < data.sql
Для меня некоторые расоны не работают. Мне нужно использовать вокруг. sqlite3 storage/db/jobs.s3db .schema jobs > schema.sql не работает, но echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sql работает нормально
Это казалось хорошим решением, но в моем случае большинство строк удаляются с помощью grep. Команда .schema генерирует схему каждой таблицы в нескольких строках, поэтому есть строка, содержащая только );, а grep удаляет все строки, содержащие );. Добавление параметра -x в grep решает эту проблему.
В качестве улучшения ответа Пола Игана это можно сделать следующим образом:
sqlite3 database.db3 '.dump "table1" "table2"' | grep '^INSERT'
--или же--
sqlite3 database.db3 '.dump "table1" "table2"' | grep -v '^CREATE'
Предостережение, конечно, в том, что у вас должна быть установлена программа grep.
Мне нравится этот. В качестве дополнительного бонуса он по-прежнему работает, если у вас есть сброшенный файл SQL, просто cat database.sql | grep '^INSERT' > database_inserts.sql (то же самое для схемы, замените на grep '^CREATE'
@trisweb, вы конечно имеете ввиду grep '^INSERT' < database.sql > database_inserts.sql, что cat лишний
Ничего лишнего. cat практически ничего не стоит в исполнении и значительно упрощает цепочку ввода-вывода. Конечно, вы также можете написать < database.sql grep '^INSERT' ..., но явный канал намного легче читать.
когда я добавляю несколько имен таблиц, как вы упомянули, это дает мне следующий результат: Использование: .dump? - preserve-rowids? ? КАК ОБРАЗЕЦ?
-1: Искать строки с помощью CREATE - бесполезная идея. Почти каждое представление или триггер, особенно если оно содержит комментарии, требует более одной строки.
Эта версия хорошо работает с символами новой строки внутри вставок:
sqlite3 database.sqlite3 .dump | grep -v '^CREATE'
На практике исключает все строки, начинающиеся с CREATE, которые с меньшей вероятностью будут содержать символы новой строки.
Любой ответ, предлагающий использовать grep для исключения строк CREATE или просто захватить строки INSERT из вывода sqlite3 $DB .dump, потерпит неудачу. Команды CREATE TABLE перечисляют по одному столбцу в строке (поэтому исключая CREATE не получится полностью), а значения в строках INSERT могут содержать встроенные символы новой строки (поэтому вы не можете захватить только строки INSERT).
for t in $(sqlite3 $DB .tables); do
echo -e ".mode insert $t\nselect * from $t;"
done | sqlite3 $DB > backup.sql
Проверено на sqlite3 версии 3.6.20.
Если вы хотите исключить определенные таблицы, вы можете отфильтровать их с помощью $(sqlite $DB .tables | grep -v -e one -e two -e three), или если вы хотите получить определенное подмножество, замените его на one two three.
В Python, Java или любом языке высокого уровня .dump не работает. Нам нужно вручную кодировать преобразование в CSV. Приведу пример на Python. Другие примеры были бы признательны:
from os import path
import csv
def convert_to_csv(directory, db_name):
conn = sqlite3.connect(path.join(directory, db_name + '.db'))
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = cursor.fetchall()
for table in tables:
table = table[0]
cursor.execute('SELECT * FROM ' + table)
column_names = [column_name[0] for column_name in cursor.description]
with open(path.join(directory, table + '.csv'), 'w') as csv_file:
csv_writer = csv.writer(csv_file)
csv_writer.writerow(column_names)
while True:
try:
csv_writer.writerow(cursor.fetchone())
except csv.Error:
break
Если у вас есть данные панели, другими словами, многие отдельные записи с идентификаторами добавляют это в внешний вид with, а также выводят сводную статистику:
if 'id' in column_names:
with open(path.join(directory, table + '_aggregate.csv'), 'w') as csv_file:
csv_writer = csv.writer(csv_file)
column_names.remove('id')
column_names.remove('round')
sum_string = ','.join('sum(%s)' % item for item in column_names)
cursor.execute('SELECT round, ' + sum_string +' FROM ' + table + ' GROUP BY round;')
csv_writer.writerow(['round'] + column_names)
while True:
try:
csv_writer.writerow(cursor.fetchone())
except csv.Error:
break
Ответ от retracile должен быть наиболее близким, но в моем случае он не работает. Один запрос на вставку сломался посередине, и экспорт просто остановился. Не уверен, в чем причина. Однако он отлично работает во время .dump.
Наконец, я написал инструмент для разделения SQL, сгенерированного из .dump:
Включать только ВСТАВКИ
sqlite3 database.db3 .dump | grep '^INSERT INTO "tablename"'
Легко реализовать, но не удастся, если какой-либо из ваших столбцов будет содержать новые строки.
Режим вставки SQLite
for t in $(sqlite3 $DB .tables); do
echo -e ".mode insert $t\nselect * from $t;"
done | sqlite3 $DB > backup.sql
Это хорошее и настраиваемое решение, но оно не работает, если в ваших столбцах есть объекты blob, такие как тип Geometry в Spaceite.
Дифференцируйте дамп со схемой
sqlite3 some.db .schema > schema.sql
sqlite3 some.db .dump > dump.sql
grep -v -f schema.sql dump > data.sql
Не знаю почему, но у меня не работает
Вероятно, на этот вопрос нет лучшего ответа, но тот, который работает для меня, - это grep the insert, учитывая, что это новые строки в значениях столбца с такое выражение
grep -Pzo "(?s)^INSERT.*\);[ \t]*$"
Чтобы выбрать таблицы, которые должны быть сброшены, .dump допускает аргумент LIKE для соответствия именам таблиц, но если этого недостаточно, вероятно, лучший вариант - простой сценарий.
TABLES='table1 table2 table3'
echo '' > /tmp/backup.sql
for t in $TABLES ; do
echo -e ".dump ${t}" | sqlite3 database.db3 | grep -Pzo "(?s)^INSERT.*?\);$" >> /tmp/backup.sql
done
или что-то более сложное, чтобы уважать внешние ключи и инкапсулировать весь дамп только в одной транзакции
TABLES='table1 table2 table3'
echo 'BEGIN TRANSACTION;' > /tmp/backup.sql
echo '' >> /tmp/backup.sql
for t in $TABLES ; do
echo -e ".dump ${t}" | sqlite3 | grep -Pzo "(?s)^INSERT.*?\);$" | grep -v -e 'PRAGMA foreign_keys=OFF;' -e 'BEGIN TRANSACTION;' -e 'COMMIT;' >> /tmp/backup.sql
done
echo '' >> /tmp/backup.sql
echo 'COMMIT;' >> /tmp/backup.sql
Учтите, что выражение grep завершится ошибкой, если ); является строкой, присутствующей в любом из столбцов.
Для его восстановления (в базе данных с уже созданными таблицами)
sqlite3 -bail database.db3 < /tmp/backup.sql
Согласно документации SQLite для Оболочка командной строки для SQLite, вы можете экспортировать таблицу SQLite (или часть таблицы) как CSV, просто установив «режим» на «csv», а затем запустив запрос для извлечения нужных строк таблицы:
sqlite> .header on
sqlite> .mode csv
sqlite> .once c:/work/dataout.csv
sqlite> SELECT * FROM tab1;
sqlite> .exit
Затем используйте команду «.import» для импорта данных CSV (значения, разделенные запятыми) в таблицу SQLite:
sqlite> .mode csv
sqlite> .import C:/work/dataout.csv tab1
sqlite> .exit
Пожалуйста, прочтите дополнительную документацию по двум рассматриваемым случаям: (1) таблица «tab1» ранее не существовала и (2) таблица «tab1» уже существует.
В какой формат? Что-нибудь конкретное, или вы просто ищете удобочитаемую резервную копию? Пожалуйста уточни.