Was ist der Unterschied zwischen verwandten SQLite-Datentypen wie INT, INTEGER, SMALLINT und TINYINT?

101

Wenn ich eine Tabelle in SQLite3 erstelle, bin ich verwirrt, wenn ich mit allen möglichen Datentypen konfrontiert werde, die ähnliche Inhalte implizieren. Kann mir jemand den Unterschied zwischen den folgenden Datentypen erklären?

INT, INTEGER, SMALLINT, TINYINT

DEC, DECIMAL

LONGCHAR, LONGVARCHAR

DATETIME, SMALLDATETIME

Gibt es irgendwo eine Dokumentation, in der die min./max. Kapazitäten der verschiedenen Datentypen? Ich denke zum Beispiel, ich habe smallinteinen größeren Maximalwert als tinyint, aber einen kleineren Wert als die ganze Zahl, aber ich habe keine Ahnung, was diese Kapazitäten sind.

Alan Harris-Reid
quelle

Antworten:

95

SQLiteTechnisch gesehen gibt es keine Datentypen, es gibt Speicherklassen in einem Manifest-Typisierungssystem, und ja, es ist verwirrend, wenn Sie an traditionelle RDBMSES gewöhnt sind. Alles intern wird als Text gespeichert. Datentypen werden basierend auf Affinitäten (ala Datentypen, die Spalten zugewiesen sind) gezwungen / in verschiedene Speicherorte konvertiert.

Das Beste, was ich Ihnen empfehlen würde, ist:

  1. Vergessen Sie vorübergehend alles, was Sie über eigenständige Datenbankdatentypen gewusst haben

  2. Lesen Sie den obigen Link von der SQLiteWebsite.

  3. Nehmen Sie die Typen aus Ihrem alten Schema und sehen Sie, worauf sie abgebildet werden SQLite

  4. Migrieren Sie alle Daten in die SQLiteDatenbank.

Hinweis: Die Einschränkungen des Datentyps können umständlich sein, insbesondere wenn Sie Zeitdauern, Datumsangaben oder ähnliche Elemente hinzufügen SQL. SQLitehat nur sehr wenige eingebaute Funktionen für solche Dinge. Bietet SQLiteIhnen jedoch eine einfache Möglichkeit, über die sqlite3_create_functionBibliotheksfunktion eigene integrierte Funktionen zum Hinzufügen von Zeitdauern und ähnlichen Dingen zu erstellen. Sie würden diese Funktion anstelle herkömmlicher gespeicherter Prozeduren verwenden.

J. Polfer
quelle
1
Danke für die Antwort und den Link. Heißt das, ich sollte mich an die Grundtypen von Text halten, numerisch, ganzzahlig, real, keine? Scheint mir sehr begrenzt zu sein, insbesondere aus MSSQL, Foxpro und Oracle. Grüße.
Alan Harris-Reid
6
Ich stimme Ihnen zu, es scheint zunächst begrenzt. Ich denke jedoch, dass Sie feststellen werden, dass SQLite sehr verzeihend ist, wie Sie Daten über das Affinitätssystem in die Datenbank einfügen. SQLite ist nicht eigenständig - es ist als kleines Datenbank-Backend konzipiert, das Sie in kleinen Anwendungen platzieren, auf die nur über eine Datenbankzugriffs-API im Code zugegriffen werden kann. Das Lösen von Problemen in SQLite ist normalerweise eine Frage der Frage, wie Sie dies tun sollen.
J. Polfer
Ich würde mich an die Grundtypen halten.
J. Polfer
4
@Alan: Es könnte nützlich sein, Spalten mit numerischer Affinität als DATEoder zu deklarieren BOOLEAN, aber ich würde nicht zwischen verschiedenen Größen von Ganzzahlen unterscheiden. Dies gilt insbesondere für den Fall INTEGER PRIMARY KEY, in dem der genaue Typname von Bedeutung ist.
dan04
"Alles wird als Text gespeichert" scheint laut sqlite.org/fileformat.html falsch zu sein , wonach Zahlen als kompakte varints / float64 gespeichert werden und nur Blob und Text als Zeichenfolgen gespeichert werden
phiresky
47

Der Unterschied ist syntaktischer Zucker. Für die Typaffinität sind nur wenige Teilzeichenfolgen der Typnamen von Bedeutung.

  • INT, INTEGER, SMALLINT, TINYINT → INTEGER-Affinität, da sie alle "INT" enthalten.
  • LONGCHAR, LONGVARCHAR → TEXT-Affinität, weil sie "CHAR" enthalten.
  • DEC, DECIMAL, DATETIME, SMALLDATETIME → NUMERIC, da sie keine der wichtigen Teilzeichenfolgen enthalten.

Die Regeln zur Bestimmung der Affinität sind auf der SQLite-Site aufgeführt .

Wenn Sie darauf bestehen , auf strikte Typisierung, können Sie es mit implementieren CHECKEinschränkungen:

CREATE TABLE T (
   N   INTEGER CHECK(TYPEOF(N) = 'integer'),
   Str TEXT CHECK(TYPEOF(Str) = 'text'),
   Dt  DATETIME CHECK(JULIANDAY(Dt) IS NOT NULL)
);

Aber ich kümmere mich nie darum.

Wie für die Kapazität jedes Typs:

  • INTEGERist immer 64-Bit signiert. Beachten Sie, dass SQLite die Speicherung kleiner Ganzzahlen hinter den Kulissen optimiert , sodass TINYINT ohnehin nicht nützlich wäre.
  • REAL ist immer 64-Bit (double ).
  • TEXTund BLOBeine maximale Größe haben, die durch ein Präprozessor-Makro bestimmt wird, das standardmäßig 1.000.000.000 Bytes verwendet.
dan04
quelle
1
Guter Trick. Beachten Sie, dass für diesen Ansatz ein Wert erforderlich ist , der eingefügt / aktualisiert werden muss, um dieselbe Speicherklasse wie die in zu haben TYPEOF. Versuche, einen TEXT einzufügen, der andernfalls von SQlite in die Speicherklasse NUMERIC / INTEGER konvertiert würde (dh eine solche Konvertierung ist verlustfrei gemäß sqlite.org/datatype3.html#affinity ), schlagen fehl. Mit anderen Worten, dieser Ansatz ist strenger als der Ad-hoc-Ansatz, den Wert einzufügen und dann die Speicherklasse, die zum Speichern dieses Werts durch SQLite verwendet wird, auf magische Weise zu validieren. Für einen freizügigeren Ansatz siehe meine Antwort unten.
Eold
10

Die meisten davon dienen der Kompatibilität. Sie haben wirklich nur Integer, Float, Text und Blob. Daten können entweder als Zahl (Unix-Zeit ist Ganzzahl, Microsoft-Zeit ist Float) oder als Text gespeichert werden.

Jay
quelle
Ich habe es für webbasierte Projekte verwendet, bei denen letztendlich ohnehin alles Text in eine HTML-Seite eingefügt wurde. Ich habe auf viel Datenkonvertierung verzichtet und nur Text für die meisten Spalten verwendet. Es hat gut geklappt.
Jay
3

NULL. Der Wert ist ein NULL-Wert.

INTEGER. Der Wert ist eine vorzeichenbehaftete Ganzzahl, die je nach Größe des Werts in 1, 2, 3, 4, 6 oder 8 Byte gespeichert wird.

REAL. Der Wert ist ein Gleitkommawert, der als 8-Byte-IEEE-Gleitkommazahl gespeichert wird.

TEXT. Der Wert ist eine Textzeichenfolge, die mithilfe der Datenbankcodierung (UTF-8, UTF-16BE oder UTF-16LE) gespeichert wird.

BLOB. Der Wert ist ein Datenblock, der genau so gespeichert wird, wie er eingegeben wurde.

user2393484
quelle
1

Als Ergänzung zur Antwort von dan04, wenn Sie blind eine NUMERICandere als die durch a dargestellte Null einfügen möchten, TEXTaber sicherstellen möchten, dass der Text in eine Zahl konvertierbar ist :

your_numeric_col NUMERIC CHECK(abs(your_numeric_col) <> 0)

Ein typischer Anwendungsfall ist eine Abfrage eines Programms, das alle Daten als Text behandelt (aus Gründen der Einheitlichkeit und Einfachheit, da SQLite dies bereits tut). Das Schöne daran ist, dass es Konstrukte wie dieses erlaubt:

INSERT INTO table (..., your_numeric_column, ...) VALUES (..., some_string, ...)

Dies ist praktisch, wenn Sie Platzhalter verwenden, da Sie solche numerischen Felder ungleich Null nicht speziell behandeln müssen. Ein Beispiel für die Verwendung des Python- sqlite3Moduls wäre:

conn_or_cursor.execute(
    "INSERT INTO table VALUES (" + ",".join("?" * num_values) + ")",   
    str_value_tuple)  # no need to convert some from str to int/float

Im obigen Beispiel werden alle Werte in str_value_tuplemaskiert und als Zeichenfolgen in Anführungszeichen gesetzt, wenn sie an SQlite übergeben werden. Da wir den Typ TYPEOFjedoch nicht explizit über überprüfen, sondern nur die Konvertierbarkeit in Typ , funktioniert er weiterhin wie gewünscht (dh SQLite speichert ihn entweder als numerische Zahl oder schlägt anderweitig fehl).

eold
quelle