Как вывести данные некоторых таблиц SQLite3?


183

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

sqlite3 db .dump

но без выгрузки схемы и выбора таблиц для выгрузки.


В каком формате? Что-нибудь конкретное, или вы просто ищете удобочитаемую резервную копию? Пожалуйста уточни.
dmckee --- котенок экс-модератора

1
Я хочу создать дамп в формате SQL, чтобы его можно было легко восстановить. Я добавил эту информацию к основному вопросу.
Пупено

Ответы:


214

Вы не говорите, что вы хотите сделать с сохраненным файлом.

Я бы использовал следующее, чтобы получить файл 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? Я вижу, как это сделать, используя переводчик, но что, если я захочу написать сценарий?
Колейфер

4
Вы можете поместить свои заявления в файл (например, sample.txt), а затем вызвать его, используя: sqlite3 db.sq3 <sample.txt
CyberFonic

« Или используйте команду .once вместо .output, и вывод будет перенаправлен только для одной следующей команды перед возвратом в консоль. Используйте .output без аргументов, чтобы снова начать запись в стандартный вывод. » SQLite docs
ruffin

156

Вы можете сделать это, получая разницу команд .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;

Я надеюсь, это поможет вам.


5
@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работает нормально
abkrim

2
Это казалось хорошим решением, но в моем случае большинство строк удаляются с помощью grep. Команда .schema генерирует схему каждой таблицы в несколько строк, поэтому есть строка, содержащая только ее );, и grep удаляет все строки, содержащие. );Добавление -xопции к grep решает эту проблему.
Сандер

38

Не лучший способ, но при аренде не нужны внешние инструменты (кроме grep, который в любом случае является стандартным для * nix)

sqlite3 database.db3 .dump | grep '^INSERT INTO "tablename"'

но вам нужно выполнить эту команду для каждой таблицы, которую вы ищете.

Обратите внимание, что это не включает схему.


1
Я использовалsqlite3 Database.s3db .dump
Jader Dias

3
Это сломается, если эти вставки будут иметь новые строки в значениях. Лучше использовать, grep -v '^CREATE'как предложено в одном из других ответов
dequis

1
Использование grep -v '^CREATE;будет прерываться, если в CREATEоператорах есть разрывы строк (что они иногда делают). Лучше всего, IMO, не автоматически CREATEудалять операторы, а вручную редактировать их. Просто используйте любой текстовый редактор, который вам нужен, и найдите CREATEи удалите эти операторы вручную. Пока база данных не огромна (а поскольку вы используете sqlite, я думаю, это примечание), это довольно просто.
Дэн Джонс

но grep создания также возьмет создание из представлений. как я могу удалить это?
Silve2611

35

Вы можете указать один или несколько табличных аргументов для специальной команды .dump, например sqlite3 db ".dump 'table1' 'table2'".


4
когда я добавляю несколько имен таблиц, как вы упомянули, это дает мне следующий вывод: Использование: .dump? - preserve-rowids? ? LIKE-PATTERN?
Mwm

1
@mwm Я наблюдаю ту же проблему в sqlite3 3.31.1 (2020/01/27). История изменений ничего не говорит об этом. (Кстати, --preserve-rowidsработает, но совсем не задокументировано.)
Инн

11

Любой ответ, который предлагает использовать 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.


9

В качестве улучшения ответа Пола Игана это можно сделать следующим образом:

sqlite3 database.db3 '.dump "table1" "table2"' | grep '^INSERT'

--или--

sqlite3 database.db3 '.dump "table1" "table2"' | grep -v '^CREATE'

Предостережение, конечно, в том, что вам нужно установить grep.


1
Мне нравится этот. В качестве дополнительного бонуса, он все еще работает, если у вас есть дамп файла SQL, просто cat database.sql | grep '^INSERT' > database_inserts.sql(то же самое для схемы, замените наgrep '^CREATE'
trisweb

2
@trisweb, конечно, ты имеешь в виду, grep '^INSERT' < database.sql > database_inserts.sqlчто catэто лишнее
Себастьян

1
Ничего лишнего в этом нет. catНе стоит в принципе ничего , чтобы выполнить и делает цепь входа к выходу намного понятнее. Конечно, вы также можете написать, < database.sql grep '^INSERT' ...но явный канал намного легче читать.
rjh

1
когда я добавляю несколько имен таблиц, как вы упомянули, это дает мне следующий вывод: Использование: .dump? - preserve-rowids? ? LIKE-PATTERN?
Mwm

-1: поиск строк с помощью CREATE - бесполезная идея. Почти для каждого просмотра или триггера, особенно, если он содержит комментарии, требуется более одной строки.
ceving

6

В 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

Если у вас есть данные панели, другими словами, многие отдельные записи с идентификаторами добавляют это к внешнему виду, а также выводит сводную статистику:

        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 

4

В соответствии с документацией SQLite для командной строки. Для SQLite вы можете экспортировать таблицу SQLite (или часть таблицы) как CSV, просто установив для «mode» значение «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» уже существует.


3

Лучший способ - взять код, который будет делать дамп 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) для актуального кода

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


3

Обзор других возможных решений

Включить только ВСТАВКИ

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 в пространственном объекте.

Diff the dump со схемой

sqlite3 some.db .schema > schema.sql
sqlite3 some.db .dump > dump.sql
grep -v -f schema.sql dump > data.sql

Не знаю почему, но у меня не работает

Другое (новое) возможное решение

Возможно, нет лучшего ответа на этот вопрос, но тот, который мне подходит, это grep вставки, принимая во внимание, что это новые строки в значениях столбцов с таким выражением

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 $1 | 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

2

Эта версия хорошо работает с символами новой строки внутри вставок:

sqlite3 database.sqlite3 .dump | grep -v '^CREATE'

На практике исключаются все строки, начинающиеся с CREATEкоторых с меньшей вероятностью содержат переводы строк


0

Ответ от retracile должен быть самым близким, но он не работает для моего случая. Один запрос вставки просто сломался в середине, и экспорт просто остановился. Не уверен, в чем причина. Однако во время работы.dump .

Наконец, я написал инструмент для разделения SQL, сгенерированного из .dump:

https://github.com/motherapp/sqlite_sql_parser/


-3

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


2
Мое намерение состояло в том, чтобы создать файл SQL, который можно легко добавить в базу данных.
Пупено
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.