¿Cuál es la diferencia entre los tipos de datos SQLite relacionados como INT, INTEGER, SMALLINT y TINYINT?

101

Al crear una tabla en SQLite3, me confundo cuando me enfrento a todos los tipos de datos posibles que implican contenidos similares, entonces, ¿alguien podría decirme la diferencia entre los siguientes tipos de datos?

INT, INTEGER, SMALLINT, TINYINT

DEC, DECIMAL

LONGCHAR, LONGVARCHAR

DATETIME, SMALLDATETIME

¿Hay alguna documentación en alguna parte que enumere los valores min./max. capacidades de los diversos tipos de datos? Por ejemplo, supongo que smallinttiene un valor máximo mayor que tinyint, pero un valor menor que el entero, pero no tengo idea de cuáles son estas capacidades.

Alan Harris-Reid
fuente

Respuestas:

95

SQLite, técnicamente, no tiene tipos de datos, hay clases de almacenamiento en un sistema de escritura de manifiesto, y sí, es confuso si estás acostumbrado a los RDBMSes tradicional . Todo, internamente, se almacena como texto. Los tipos de datos se coaccionan / convierten en varias ubicaciones de almacenamiento según las afinidades (tipos de datos asignados a las columnas).

Lo mejor que te recomendaría hacer es:

  1. Olvídese temporalmente de todo lo que solía saber sobre los tipos de datos de bases de datos independientes

  2. Lea el enlace anterior del SQLitesitio.

  3. Tome los tipos basados ​​en su esquema anterior y vea a qué se asignan en SQLite

  4. Migre todos los datos a la SQLitebase de datos.

Nota: Las limitaciones del tipo de datos pueden resultar engorrosas, especialmente si agrega duraciones de tiempo, fechas o cosas de esa naturaleza en SQL. SQLitetiene muy pocas funciones integradas para ese tipo de cosas. Sin embargo, SQLiteproporciona una manera fácil de crear sus propias funciones integradas para agregar duraciones de tiempo y cosas de esa naturaleza, a través de la sqlite3_create_functionfunción de biblioteca. Utilizaría esa instalación en lugar de los procedimientos almacenados tradicionales.

J. Polfer
fuente
1
Gracias por la respuesta y el enlace. ¿Significa esto que debo ceñirme a los tipos básicos de texto, numérico, entero, real, ninguno? Me parece muy limitado, especialmente viniendo de MSSQL, Foxpro y Oracle. Saludos.
Alan Harris-Reid
6
Estoy de acuerdo contigo, parece limitado al principio. Sin embargo, creo que encontrará que SQLite es muy indulgente con la forma en que coloca datos en la base de datos a través de su sistema de afinidad. SQLite no es independiente: está diseñado para ser un pequeño backend de base de datos que se coloca en aplicaciones pequeñas para acceder solo a través de una API de acceso a la base de datos en el código. Resolver problemas en SQLite suele ser una cuestión de averiguar cómo quieren que lo haga.
J. Polfer
Me quedaría con los tipos básicos.
J. Polfer
4
@Alan: Puede que le resulte útil declarar columnas de afinidad numérica como DATEo BOOLEAN, pero no me molestaría en distinguir entre diferentes tamaños de números enteros. Esto es especialmente cierto para el caso de INTEGER PRIMARY KEY, el único caso en el que importa el nombre exacto del tipo.
dan04
"Todo se almacena como texto" parece estar mal de acuerdo con sqlite.org/fileformat.html , que dice que los números se almacenan como varints compactos / float64, y solo blob y texto se almacenan como cadenas
phiresky
47

La diferencia es el azúcar sintáctico. Solo unas pocas subcadenas de los nombres de tipo importan en lo que respecta a la afinidad de tipos.

  • INT, INTEGER, SMALLINT, TINYINT → INTEGER afinidad, porque todos contienen "INT".
  • LONGCHAR, LONGVARCHAR → afinidad TEXT, porque contienen "CHAR".
  • DEC, DECIMAL, DATETIME, SMALLDATETIME → NUMERIC, porque no contienen ninguna de las subcadenas que importan.

Las reglas para determinar la afinidad se enumeran en el sitio de SQLite .

Si insiste en una escritura estricta, puede implementarla con CHECKrestricciones:

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

Pero nunca me preocupo por eso.

En cuanto a la capacidad de cada tipo:

  • INTEGERsiempre tiene signo de 64 bits. Tenga en cuenta que SQLite optimiza el almacenamiento de pequeños enteros detrás de escena, por lo que TINYINT no sería útil de todos modos.
  • REALes siempre de 64 bits ( double).
  • TEXTy BLOBtener un tamaño máximo determinado por una macro de preprocesador, cuyo valor predeterminado es 1.000.000.000 bytes.
dan04
fuente
1
Buen truco. Tenga en cuenta que este enfoque requiere que se inserte / actualice un valor para tener la misma clase de almacenamiento que la de TYPEOF. Por lo tanto, los intentos de insertar un TEXTO que de otro modo se convertiría a la clase de almacenamiento NUMERIC / INTEGER por SQlite (es decir, tal conversión no tiene pérdidas según sqlite.org/datatype3.html#affinity ) fallarían. En otras palabras, este enfoque es más estricto que el enfoque ad-hoc de insertar el valor y luego de alguna manera validar mágicamente la clase de almacenamiento utilizada para almacenar ese valor por SQLite. Para un enfoque más permisivo, vea mi respuesta a continuación.
eold
10

La mayoría de ellos están ahí por compatibilidad. Realmente solo tienes integer, float, text y blob. Las fechas se pueden almacenar como un número (el tiempo de Unix es un número entero, el tiempo de Microsoft es flotante) o como texto.

Arrendajo
fuente
Lo he usado para proyectos basados ​​en la web donde, en última instancia, todo terminó siendo texto en una página html de todos modos. Prescindí de una gran cantidad de conversión de datos y solo usé texto para la mayoría de las columnas. Funcionó bien.
Jay
3

NULL. El valor es un valor NULO.

INTEGER. El valor es un entero con signo, almacenado en 1, 2, 3, 4, 6 u 8 bytes dependiendo de la magnitud del valor.

REAL. El valor es un valor de coma flotante, almacenado como un número de coma flotante IEEE de 8 bytes.

TEXT. El valor es una cadena de texto, almacenada usando la codificación de la base de datos (UTF-8, UTF-16BE o UTF-16LE).

BLOB. El valor es una masa de datos, almacenada exactamente como se ingresó.

usuario2393484
fuente
1

Como una adición a la respuesta de dan04, si desea insertar ciegamente un NUMERICotro que no sea cero representado por un, TEXTpero asegúrese de que el texto sea ​​convertible a numérico:

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

El caso de uso típico es una consulta de un programa que trata todos los datos como texto (para uniformidad y simplicidad, ya que SQLite ya lo hace). Lo bueno de esto es que permite construcciones como esta:

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

lo cual es conveniente en caso de que esté usando marcadores de posición porque no tiene que manejar campos numéricos distintos de cero especialmente. Un ejemplo usando el sqlite3módulo de Python sería,

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

En el ejemplo anterior, todos los valores de str_value_tuplese escaparán y se citarán como cadenas cuando se pasen a SQlite. Sin embargo, dado que no estamos verificando explícitamente el tipo a través, TYPEOFsino solo la convertibilidad a tipo , seguirá funcionando como se desee (es decir, SQLite lo almacenará como numérico o fallará de otra manera).

viejo
fuente