Pięć klas przechowywania zamiast wielu typów
SQLite zapisuje każdą wartość jako jedną z pięciu klas przechowywania (storage classes):
NULL: brak wartości.INTEGER: liczba całkowita ze znakiem, od 1 do 8 bajtów zależnie od wielkości.REAL: 8-bajtowa liczba zmiennoprzecinkowa IEEE.TEXT: ciąg znaków zapisany w kodowaniu bazy (zwykle UTF-8).BLOB: surowe bajty zapisane dokładnie tak, jak je podano.
I tyle. Nie ma osobnego BOOLEAN, DATETIME, VARCHAR ani DECIMAL. Inne bazy mają dziesiątki typów, SQLite ma pięć, a wszystko inne jest zbudowane na nich.
typeof() podaje rzeczywistą klasę przechowywania każdej wartości. Zobaczysz integer, real, text, blob. Te cztery i do tego null to wszystko, co zna SQLite.
Typowanie jest dynamiczne
Oto część, która zaskakuje osoby przychodzące z Postgres lub MySQL. W SQLite (bez STRICT) typ zadeklarowany dla kolumny to raczej sugestia niż umowa. Rzeczywisty typ żyje razem z każdą wartością:
Oba wiersze zostały przyjęte. Kolumna id w jednym wierszu ma liczbę całkowitą, a w drugim tekst. body ma tekst i liczbę całkowitą. SQLite chętnie zapisuje wartości dowolnej klasy w dowolnej kolumnie.
To dynamiczne typowanie i świadoma decyzja projektowa. Dzięki niemu SQLite wybacza wiele przy prototypowaniu i szybkich skryptach. Oznacza to jednak też, że literówka w kodzie aplikacji może latami po cichu zapisywać dane w złej postaci. Jeśli ten kompromis ci przeszkadza (a w większości schematów produkcyjnych powinien), odpowiedzią są tabele STRICT. Wkrótce do nich dojdziemy.
Type affinity w jednym akapicie
Typ zadeklarowany dla kolumny nie jest ignorowany: nadaje kolumnie affinity (powinowactwo typu). Gdy wstawiasz wartość, SQLite próbuje przekonwertować ją w stronę affinity kolumny, jeśli istnieje czysta konwersja. Kolumna TEXT, która dostaje liczbę 42, zapisze ją jako tekst '42'. Kolumna INTEGER, która dostaje ciąg '42', zapisze go jako liczbę całkowitą 42. Jeśli konwersja powodowałaby utratę informacji, zostaje oryginalny typ.
Pierwszy wiersz: liczba całkowita 42 została zamieniona na tekst '42', a ciąg '100' na liczbę całkowitą 100. Drugi wiersz: '3.5' nie dało się bezstratnie zamienić na INTEGER, więc zostało tekstem. Affinity ma własną stronę, która pojawi się wkrótce. Na razie wystarczy wiedzieć, że typ kolumny wpływa na sposób zapisu, nawet jeśli go nie wymusza.
Wartości logiczne
Nie ma klasy przechowywania BOOLEAN. SQLite zapisuje wartości logiczne jako liczby całkowite: 0 dla fałszu i 1 dla prawdy:
Słowa kluczowe TRUE i FALSE są rozpoznawane (od SQLite 3.23) i zamieniane na 1 i 0. Deklaracja BOOLEAN nadaje kolumnie affinity liczbowe, ale nie ogranicza jej do 0/1: bez STRICT możesz wstawić 'maybe' i SQLite nie zaprotestuje.
Daty i czasy
Nie ma też DATETIME. Wybierasz jedno z trzech kodowań, a funkcje dat SQLite działają na każdym z nich:
TEXTjako ISO-8601:'2026-04-23 14:30:00'.REALjako numery dni juliańskich.INTEGERjako sekundy od epoki Unix.
Tekst ISO-8601 to najczęstszy wybór: sortuje się poprawnie jako ciąg znaków, jest czytelny dla człowieka, a wbudowane funkcje (date(), time(), datetime(), strftime(), julianday()) go obsługują. Wybierz jedno kodowanie na kolumnę i się go trzymaj. Mieszanie formatów w jednej kolumnie to coś, co zemści się pół roku później.
VARCHAR, CHAR i inne znajome nazwy
SQLite akceptuje nazwy typów znane z innych baz: VARCHAR(255), CHAR(10), NVARCHAR, DECIMAL(10,2), DOUBLE, FLOAT, INT, BIGINT, MEDIUMINT. Wszystkie parsują się bez problemu. Po prostu sprowadzają się do jednej z pięciu klas przechowywania według reguł affinity.
VARCHAR(255) nie wymusza limitu 255 znaków, bo SQLite ignoruje długość. DECIMAL(10, 2) nie przechowuje liczby dziesiętnej o stałej precyzji: dostaje affinity liczbowe i jest przechowywany jako INTEGER lub REAL. Te nazwy istnieją wyłącznie po to, żeby schematy skopiowane z innych baz działały. Nie przynoszą ograniczeń, które oznaczają gdzie indziej.
Jeśli potrzebujesz dokładnej arytmetyki dziesiętnej dla pieniędzy, zapisuj grosze jako INTEGER. Zmiennoprzecinkowy REAL prędzej czy później wprowadzi błędy zaokrągleń na trzecim miejscu po przecinku.
NULL to klasa przechowywania
NULL to nie tylko "brak wartości", ale wartość z własną klasą przechowywania, zwracaną przez typeof():
b jest raportowane jako null. Ma to znaczenie, bo NULL nie jest równe niczemu, nawet innemu NULL. b = NULL nigdy nie jest prawdą, trzeba napisać b IS NULL. Porządnie omawia to strona o operatorach i NULL w dalszej części, ale zaczyna się to tutaj, od klasy przechowywania.
Przechowywanie bajtów w BLOB
BLOB zapisuje surowe bajty dosłownie. Przydaje się do małych obrazów, skrótów (hashy), zakodowanych danych i wszystkiego, co nie jest tekstem ani liczbą:
Literał x'...' pozwala zapisywać bloby w SQL szesnastkowo. W kodzie aplikacji zwykle przekazuje się tablicę bajtów przez parametr. length() na blobie zwraca liczbę bajtów, a nie znaków.
Praktyczna uwaga: SQLite bez problemu przechowuje duże bloby, ale przeciąganie 50-megabajtowego bloba przez każde zapytanie, które dotyka wiersza, jest wolne. Duże pliki trzymaj na dysku, a w bazie zapisuj tylko ścieżkę.
Co warto zapamiętać
- Pięć klas przechowywania (
NULL,INTEGER,REAL,TEXT,BLOB) obejmuje wszystko. - Wartości logiczne to liczby całkowite, a daty to tekst, liczba rzeczywista lub całkowita (twój wybór).
- Zadeklarowane typy kolumn to wskazówki, a nie umowy (chyba że używasz
STRICT). VARCHAR(255)i podobne parsują się, ale nie wymuszają długości ani precyzji, które oznaczają gdzie indziej.typeof(value)to twój przyjaciel, gdy nie masz pewności, co naprawdę jest zapisane.
Dalej: type affinity
Zachowanie typu "wskazówka", które tu pobieżnie omówiliśmy, opiera się na precyzyjnym zestawie reguł: pięciu klasach affinity wyprowadzanych z zadeklarowanej nazwy typu i stosowanych przy każdym wstawieniu. To temat następnej strony i klucz do przewidywania, co SQLite naprawdę zrobi z przekazanymi wartościami.
Najczęściej zadawane pytania
Jakie typy danych obsługuje SQLite?
SQLite ma pięć klas przechowywania: NULL, INTEGER, REAL, TEXT i BLOB. Każda wartość w bazie jest zapisana jako jedna z nich. Znane nazwy, takie jak VARCHAR(255), DATETIME czy BOOLEAN, są akceptowane w CREATE TABLE dla zgodności, ale przy zapisie sprowadzają się do jednej z pięciu klas.
Czy SQLite ma typ logiczny albo typ daty i czasu?
Nie jako osobne klasy przechowywania. Wartości logiczne są zapisywane jako INTEGER (0 i 1), choć SQLite rozpoznaje też słowa kluczowe TRUE i FALSE. Daty i czasy zapisuje się jako TEXT (ciągi ISO-8601), REAL (numery dni juliańskich) lub INTEGER (sekundy od epoki Unix). Ty wybierasz kodowanie, a funkcje dat działają na wszystkich trzech.
Dlaczego typowanie w SQLite nazywa się dynamicznym?
W większości baz kolumna zadeklarowana jako INTEGER odrzuca teksty. W SQLite (domyślnie) zadeklarowany typ jest wskazówką: rzeczywisty typ podróżuje z każdą wartością, więc kolumna TEXT może przechowywać liczbę całkowitą, jeśli ją wstawisz. Ta elastyczność czasem się przydaje, a czasem jest pułapką. Tabele STRICT ją wyłączają.