CREATE TABLE definiuje schemat
Każdy fragment danych strukturalnych w SQLite żyje w tabeli, a każda tabela zaczyna się od instrukcji CREATE TABLE. Podajesz nazwę, wymieniasz kolumny i opcjonalnie dodajesz ograniczenia. SQLite zapisuje schemat w pliku bazy i tabela jest gotowa do użycia.
Najmniejszy użyteczny przykład:
Trzy kolumny, jeden klucz główny, jedna reguła NOT NULL. SQLite automatycznie wypełnił id, bo to całkowitoliczbowy klucz główny, i pozwolił, żeby email w drugim wierszu było NULL, bo nic temu nie zabraniało. To cały kształt: nazwa, kolumny, ograniczenia. Wszystko inne na tej stronie to jego warianty.
Składnia kawałek po kawałku
Definicja kolumny to name TYPE constraint constraint .... W klasycznym SQLite typ jest opcjonalny (więcej o tym na stronie o type affinity), ale dobrą praktyką jest zawsze go podawać, bo polegają na nim czytelnicy i narzędzia.
Kilka rzeczy, na które warto zwrócić uwagę:
- Ograniczenia łączy się spacjami:
NOT NULL UNIQUEnaskuoznacza, że obowiązują obie reguły. DEFAULT 1nain_stockpozwala pominąć tę kolumnę wINSERT.- SQLite używa
INTEGERdla wartości logicznych, bo nie ma natywnego typuBOOLEAN.0to fałsz,1to prawda. - Przecinek po ostatniej kolumnie to błąd składni. SQL jest tu bardziej rygorystyczny niż JavaScript.
IF NOT EXISTS: bez awarii przy ponownym uruchomieniu
Uruchom CREATE TABLE na bazie, która już ma tę tabelę, a SQLite zgłosi błąd:
Error: table users already exists
Za pierwszym razem to w porządku, za setnym irytuje. IF NOT EXISTS sprawia, że instrukcja nic nie robi, gdy tabela już istnieje:
Drugie CREATE TABLE nic nie robi: bez błędu i bez zmiany schematu. To forma, której chcesz w kodzie startowym, skryptach migracji i wszędzie tam, gdzie ten sam SQL może się wykonać więcej niż raz.
Uwaga jednak: IF NOT EXISTS sprawdza tylko nazwę. Jeśli tabela o tej nazwie istnieje, ale ma inne kolumny, SQLite zostawia ją w spokoju. Nie "naprawi" ani nie "zaktualizuje" schematu za ciebie. Do tego służą migracje.
Ograniczenia: reguły, które podróżują ze schematem
Ograniczenia pozwalają przenieść walidację do samej bazy. Te, po które będziesz sięgać bez przerwy:
PRIMARY KEY: jednoznacznie identyfikuje wiersz. Więcej o tym w dokumencie o kluczach głównych.NOT NULL: kolumna musi mieć wartość.DEFAULT value: używane, gdyINSERTpomija kolumnę. Może to być literał albo wyrażenie, na przykładdatetime('now').CHECK (expr): musi dawać prawdę dla każdego wiersza.UNIQUE (col, col): ograniczenie na poziomie tabeli, które wymusza unikalność kombinacji.
Ograniczenia działają przy każdym INSERT i UPDATE. Wiersz, który narusza któreś z nich, zostaje odrzucony, a instrukcja się nie udaje. Wyłapanie złych danych w bazie jest dużo tańsze niż wyłapywanie ich, gdy już rozejdą się po aplikacji.
Klucze obce
Klucz obcy mówi: "ta kolumna wskazuje na wiersz w innej tabeli". Utrzymuje spójność danych: nie możesz odwołać się do użytkownika, który nie istnieje, a (z odpowiednimi opcjami) usunięcie użytkownika może kaskadowo usunąć jego zamówienia.
Pułapka SQLite, którą warto zapamiętać: egzekwowanie kluczy obcych jest domyślnie wyłączone. Musisz uruchomić PRAGMA foreign_keys = ON w każdym połączeniu, w którym ograniczenia mają być sprawdzane. Większość sterowników aplikacyjnych robi to za ciebie albo udostępnia odpowiednie ustawienie. Jeśli twój nie, uruchom tę pragmę zaraz po połączeniu.
ON DELETE CASCADE oznacza tutaj, że usunięcie użytkownika automatycznie usuwa jego posty. Inne opcje to SET NULL, RESTRICT i domyślne NO ACTION, które odrzuca usunięcie, jeśli istnieją wiersze podrzędne.
CREATE TABLE AS SELECT
Czasem potrzebujesz szybkiej kopii wyniku zapytania jako nowej tabeli: na migawkę, kopię zapasową albo tabelę roboczą podczas analizy. Służy do tego CREATE TABLE ... AS SELECT:
Nowa tabela kopiuje nazwy kolumn, typy (w miarę możliwości) i dane. Równie ważne jest to, czego nie kopiuje: brak klucza głównego, brak NOT NULL, brak indeksów i kluczy obcych. To płaska migawka. Traktuj ją jako punkt wyjścia do doraźnej pracy, a nie sposób na klonowanie prawdziwego schematu.
Jeśli chcesz samą strukturę bez danych, dodaj WHERE 0:
Dostajesz pustą tabelę o tym samym kształcie kolumn, co przydaje się przy tabelach archiwalnych, które wypełnisz później.
Tabele tymczasowe
Tabela TEMP istnieje tylko w bieżącym połączeniu z bazą. Zamknij połączenie, a zniknie: bez sprzątania i bez pozostałości w schemacie:
Dobre zastosowania: przechowywanie wierszy dla wieloetapowego zapytania, trzymanie wyników pośrednich zbyt zawiłych na CTE, izolowanie danych jednego połączenia w długiej sesji. CREATE TEMP TABLE i CREATE TEMPORARY TABLE znaczą to samo.
Możesz to też łączyć z AS SELECT: CREATE TEMP TABLE snapshot AS SELECT ... to popularny wzorzec zamrażania zbioru wyników w trakcie analizy.
Cytowanie nazw
Zwykle nazwy kolumn i tabel to zwykłe identyfikatory. Jeśli musisz użyć słowa zastrzeżonego albo nazwy ze spacjami, otocz ją cudzysłowami (standard SQL) albo grawisami (zwyczaj z MySQL, który SQLite też akceptuje):
Działa, ale przy każdym odwołaniu do tabeli jest to utrudnienie. Wybieraj zwykłe nazwy, takie jak orders, selection, user_id, i w ogóle unikaj cytowania.
Realistyczny przykład
Składając wszystko razem: mały schemat aplikacji do zadań z IF NOT EXISTS, żeby mógł się wykonywać przy każdym starcie:
To schemat, który można wdrożyć: idempotentne tworzenie, egzekwowane klucze obce, CHECK pilnujący, żeby done miało sensowną wartość, rozsądne wartości domyślne i znaczniki czasu, które wypełniają się same.
Dalej: typy danych
CREATE TABLE pozwala pisać INTEGER, TEXT, REAL, ale SQLite słynie z luźnego podejścia do przechowywania tych wartości. Następna strona omawia pięć klas przechowywania, których SQLite naprawdę używa, i wyjaśnia, dlaczego zadeklarowany typ nie zawsze jest typem, który dostajesz.
Najczęściej zadawane pytania
Jak utworzyć tabelę w SQLite?
Użyj CREATE TABLE name (column1 TYPE, column2 TYPE, ...). Każda kolumna dostaje nazwę i opcjonalny typ, a do tego możesz dodać ograniczenia, takie jak PRIMARY KEY, NOT NULL czy DEFAULT. Instrukcja wykonuje się od razu, a tabela zostaje zapisana w pliku bazy.
Co robi IF NOT EXISTS w CREATE TABLE?
CREATE TABLE IF NOT EXISTS name (...) tworzy tabelę tylko wtedy, gdy tabela o tej nazwie jeszcze nie istnieje. Bez tego ponowne uruchomienie skryptu na istniejącej bazie zgłasza błąd table already exists. To standardowe zabezpieczenie w skryptach migracji i kodzie startowym aplikacji.
Czy w SQLite mogę utworzyć tabelę z wyniku SELECT?
Tak, CREATE TABLE new_name AS SELECT ... buduje nową tabelę z wyniku zapytania. Nowa tabela kopiuje nazwy kolumn i dane, ale nie kopiuje ograniczeń, kluczy głównych ani indeksów z tabeli źródłowej. Używaj tego do migawek i tabel roboczych, a nie jako zamiennika prawdziwego schematu.
Czym różni się tabela tymczasowa od zwykłej?
CREATE TEMP TABLE (lub CREATE TEMPORARY TABLE) tworzy tabelę, która istnieje tylko w bieżącym połączeniu z bazą i znika, gdy połączenie się zamyka. Zwykłe tabele są zapisywane w pliku bazy. Tabele tymczasowe przydają się do przechowywania pośrednich wyników zapytań bez zaśmiecania schematu.