Eksport to zadanie powłoki, a nie instrukcja SQL
SQLite nie ma COPY ... TO ani SELECT INTO OUTFILE jak Postgres czy MySQL. Eksport danych odbywa się w powłoce wiersza poleceń sqlite3, za pomocą poleceń z kropką: .mode, .headers, .output, .dump. Gdy znasz te cztery, możesz wygenerować CSV, JSON, zwykły tekst albo pełny zrzut SQL z dowolnej bazy.
Model myślowy: mówisz powłoce, jak formatować wyniki (.mode), czy dołączać nazwy kolumn (.headers) i dokąd wysyłać wynik (.output). Potem uruchamiasz zapytanie, a jego wyniki trafiają do pliku.
Przygotujmy małą bazę do ćwiczeń:
Trzy wiersze, cztery kolumny. Wyeksportujemy je w kilku formatach.
CSV: .mode csv z nagłówkami
CSV to najpopularniejszy format eksportu: rozumieją go arkusze kalkulacyjne, potoki danych i większość innych narzędzi. W powłoce sqlite3:
sqlite> .mode csv
sqlite> .headers on
sqlite> .output users.csv
sqlite> SELECT * FROM users;
sqlite> .output stdout
Co się właśnie stało:
.mode csvformatuje każdy wiersz jako wartości rozdzielone przecinkami i ujmuje w cudzysłowy pola zawierające przecinki, cudzysłowy lub znaki nowej linii..headers ondodaje pierwszy wiersz z nazwami kolumn. Bez tego CSV nie ma nagłówka, a zwykle nie o to chodzi..output users.csvprzekierowuje wyniki do pliku. Od tej chwili wynik zapytań trafia tam, a nie na ekran.SELECTwykonuje się i po cichu zapisuje do pliku..output stdoutprzełącza wynik z powrotem na terminal, żeby było widać wyniki kolejnego zapytania.
Powstały plik:
id,name,email,signup_date
1,"Ada Lovelace",ada@example.com,2025-01-15
2,"Boris Johnson",boris@example.com,2025-02-03
3,"Carmen Diaz",carmen@example.com,2025-03-22
Możesz wyeksportować wynik dowolnego zapytania, nie tylko całe tabele: filtruj, łącz, agreguj, a potem przekieruj:
sqlite> .output recent_users.csv
sqlite> SELECT name, email FROM users WHERE signup_date >= '2025-02-01';
sqlite> .output stdout
Jedna linia z poziomu powłoki systemu
Wcale nie musisz wchodzić do interaktywnej powłoki. Przekaż polecenia z kropką i SQL do sqlite3 z powłoki systemu operacyjnego:
sqlite3 mydb.sqlite <<EOF
.headers on
.mode csv
.output users.csv
SELECT * FROM users;
EOF
Tej formy potrzebujesz w skryptach i zadaniach cron: powtarzalna, bez ręcznego wpisywania. .output działa tylko w obrębie sesji, więc nigdzie nie zostawia stanu.
JSON: .mode json
Przy eksportach dla aplikacji webowej albo narzędzia, które przyjmuje JSON, .mode json generuje tablicę obiektów, po jednym na wiersz:
sqlite> .mode json
sqlite> .output users.json
sqlite> SELECT * FROM users;
sqlite> .output stdout
Plik:
[{"id":1,"name":"Ada Lovelace","email":"ada@example.com","signup_date":"2025-01-15"},
{"id":2,"name":"Boris Johnson","email":"boris@example.com","signup_date":"2025-02-03"},
{"id":3,"name":"Carmen Diaz","email":"carmen@example.com","signup_date":"2025-03-22"}]
W JSON nagłówki są niejawne (to klucze), więc .headers nie ma tu zastosowania. Jeśli chcesz własny kształt, na przykład zagnieżdżone obiekty albo zmienione nazwy pól, zbuduj go w zapytaniu za pomocą json_object():
Dostajesz ciągi JSON dla każdego wiersza z pełną kontrolą nad strukturą. Połącz to z json_group_array(), żeby zebrać cały wynik w jeden dokument JSON.
Pełny zrzut SQL: .dump
.dump różni się zasadniczo od CSV czy JSON. Tworzy plik .sql zawierający schemat i wszystkie dane w postaci instrukcji CREATE TABLE i INSERT, czyli dość, żeby odbudować bazę od zera:
sqlite3 mydb.sqlite .dump > backup.sql
Fragment tego, co powstaje:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
signup_date TEXT NOT NULL
);
INSERT INTO users VALUES(1,'Ada Lovelace','ada@example.com','2025-01-15');
INSERT INTO users VALUES(2,'Boris Johnson','boris@example.com','2025-02-03');
INSERT INTO users VALUES(3,'Carmen Diaz','carmen@example.com','2025-03-22');
COMMIT;
Przywracanie to operacja odwrotna: przekaż plik z powrotem do nowej bazy:
sqlite3 restored.sqlite < backup.sql
.dump to właściwe narzędzie do kopii zapasowych, migawek danych testowych w systemie kontroli wersji i przenoszenia baz między maszynami. Zachowuje indeksy, wyzwalacze, widoki, czyli wszystko, co jest w schemacie.
Zrzut pojedynczej tabeli
.dump przyjmuje nazwę tabeli (albo wzorzec), żeby ograniczyć wynik:
sqlite3 mydb.sqlite ".dump users" > users_only.sql
To zrzuca tylko schemat i wiersze tabeli users. Przydaje się, gdy chcesz skopiować jedną tabelę do innej bazy bez przenoszenia reszty. Możesz też użyć wzorca: .dump 'log_%' zrzuca każdą tabelę zaczynającą się od log_.
Schemat bez danych
Czasem potrzebujesz struktury bez wierszy: do dokumentacji, czystego środowiska deweloperskiego albo porównania schematów między bazami. .schema wypisuje tylko instrukcje CREATE:
sqlite3 mydb.sqlite .schema > schema.sql
Dodaj nazwę tabeli, żeby dostać tylko jedną:
sqlite3 mydb.sqlite ".schema users" > users_schema.sql
Wynik to zwykły SQL (CREATE TABLE, CREATE INDEX, CREATE TRIGGER), gotowy do uruchomienia na pustej bazie.
Inne przydatne tryby
.mode ma więcej opcji niż CSV i JSON. Kilka, które warto znać:
.mode column -- wyrównane kolumny, wygodne do czytania w terminalu
.mode markdown -- tabele rozdzielone kreskami pionowymi, zgodne z GitHubem
.mode html -- wynik jako <table> w HTML
.mode tabs -- wartości rozdzielone tabulatorami (TSV)
.mode insert users -- generuje instrukcje INSERT dla podanej tabeli
.mode quote -- wartości w cudzysłowach SQL, przydatne do podglądu
.mode markdown świetnie nadaje się do wklejania wyników zapytań do README albo pull requesta. .mode insert <table> to szybki sposób na wygenerowanie danych startowych: uruchom SELECT, przechwyć instrukcje INSERT i wklej je do pliku z danymi testowymi.
sqlite> .mode insert users
sqlite> .output seed.sql
sqlite> SELECT * FROM users WHERE signup_date >= '2025-02-01';
sqlite> .output stdout
Kilka praktycznych uwag
.output stdout(albo.outputbez argumentu) przywraca wynik w terminalu. Jeśli o tym zapomnisz, wyniki następnego zapytania po cichu znikną w pliku.- Eksport do CSV nie zachowuje typów. W pliku wszystko staje się tekstem, a ponowny import wymaga schematu docelowego, który je zinterpretuje. Użyj
.dump, jeśli liczy się wierne przeniesienie danych do innej bazy SQLite. - Duże eksporty są strumieniowane.
.outputzapisuje wiersze w miarę ich generowania, więc bez problemu zrzucisz tabele większe niż pamięć RAM. - Przy kopii zapasowej działającej bazy
.dumpsię sprawdzi, ale dedykowane polecenie.backup(omówione dalej w materiałach) jest szybsze i bezpieczniejsze, bo korzysta z API kopii online w SQLite.
Dalej: odczytywanie danych
Masz już pełny obraz zapisywania danych: INSERT, UPDATE, DELETE, UPSERT, RETURNING, import z CSV i eksport z powrotem na zewnątrz. Teraz druga połowa pracy z bazą danych: wydajne odczytywanie danych. Instrukcja SELECT to miejsce, w którym spędzisz najwięcej czasu, i jest tematem następnej strony.
Najczęściej zadawane pytania
Jak wyeksportować tabelę SQLite do CSV?
W powłoce sqlite3 przełącz się w tryb CSV, włącz nagłówki, skieruj wynik do pliku i uruchom zapytanie: .mode csv, .headers on, .output users.csv, a potem SELECT * FROM users;. Na koniec uruchom .output stdout, żeby wyniki znów trafiały do terminala.
Czym różni się .dump od eksportu do CSV?
.dump tworzy plik .sql z instrukcjami CREATE TABLE i INSERT, czyli wszystkim, co potrzebne do odbudowania bazy od zera. CSV eksportuje tylko wiersze jednego zapytania lub tabeli, bez schematu. Używaj .dump do kopii zapasowych i migracji, a CSV do przekazywania danych do arkuszy kalkulacyjnych i innych narzędzi.
Czy mogę wyeksportować wyniki zapytania SQLite do JSON?
Tak. Możesz ustawić w powłoce .mode json i uruchomić dowolne SELECT albo użyć wbudowanych funkcji json_object() i json_group_array(), żeby zbudować JSON w samym zapytaniu. .mode json jest prostsze przy doraźnych eksportach, a funkcje dają pełną kontrolę nad kształtem wyniku.