Як я скидаю дані деяких таблиць SQLite3?


183

Як я скидаю дані та лише дані, а не схему, деяких таблиць SQLite3 бази даних (не всіх таблиць)? Дамп повинен бути у форматі SQL, оскільки він повинен бути легко повторно введений у базу даних пізніше і робити це з командного рядка. Щось на зразок

sqlite3 db .dump

але без скидання схеми та вибору таблиць, які потрібно скидати.


До якого формату? Що-небудь, зокрема, чи ви просто шукаєте для людей, які читають резервні копії? Будь ласка уточніть.
dmckee --- кошеня колишнього модератора

1
Я хочу перейти до формату SQL, щоб легко відновити його. Я додав цю інформацію до головного питання.
pupeno

Відповіді:


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-операторів? Я бачу, як це зробити за допомогою інтерпретатора, але що робити, якщо я хотів написати сценарій?
coleifer

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
Це здавалося хорошим рішенням, але в моєму випадку більшість ліній фактично видаляються грепом. Команда .schema генерує схему кожної таблиці в декількох рядках, тому існує лише рядок, що містить );, і grep видаляє всі рядки, що містять );Додавання -xопції grep вирішує цю проблему.
Сандер

38

Не найкращий спосіб, але в оренді не потрібні зовнішні інструменти (за винятком грепа, що все одно є стандартним для * nix коробок)

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

але вам потрібно виконати цю команду для кожної таблиці, яку ви шукаєте, хоча.

Зауважте, що це не включає схему.


1
Я використовувавsqlite3 Database.s3db .dump
Jader Dias

3
Це порушиться, якщо ці вставки мають нові значення у значеннях. Краще використовувати так, grep -v '^CREATE'як пропонується в одній з інших відповідей
декіс

1
використання grep -v '^CREATE;перерветься, якщо в CREATEоператорах є перерви рядків (що вони іноді роблять). Найкраще, IMO, це зовсім не автоматично викреслювати CREATEвисловлювання, а редагувати їх вручну. Просто використовуйте потрібний текстовий редактор, а також шукайте CREATEта видаляйте ці заяви вручну. Поки база даних не є величезною (а оскільки ви використовуєте sqlite, я думаю, це відзначити), то це досить просто.
Dan Jones

але хватість твору також візьме творення з переглядів. як я можу це видалити?
Silve2611

35

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


4
коли я додаю кілька імен таблиць, як ви згадали, це дає мені такий вихід: Використання: .dump? - зберегти-rowids? «ПОДАЧА»
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'

Застереження, звичайно, полягає в тому, що ви повинні встановити греп.


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? - зберегти-rowids? «ПОДАЧА»
mwm

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

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, просто встановивши "режим" на "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

Це приємне та налаштоване рішення, але воно не працює, якщо у ваших стовпцях у просторі є об'єкти, що перебувають у формі "Геометрія".

Розріжте дамп із схемою

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

Не знаю чому, але не працює для мене

Ще одне (нове) можливе рішення

Напевно, немає найкращої відповіді на це запитання, але одна, яка працює для мене, - це греп вставки, враховуючи, що це нові рядки у значеннях стовпця з виразом, як це

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

Відповідь за допомогою ретранслятора повинна бути найближчою, але це не працює для мого випадку. Один запит на вставлення просто зламався посередині, і експорт просто припинився. Не впевнений, в чому причина. Однак це добре працює під час .dump.

Нарешті я написав інструмент для розбиття SQL, сформованого з .dump:

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


-3

Ви можете зробити вибір у таблицях, вставляючи коми після кожного поля для створення csv, або використовувати інструмент GUI, щоб повернути всі дані та зберегти їх у csv.


2
Мій намір полягав у створенні файлу SQL, який легко міг би знову додати до БД.
pupeno
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.