Tipos de datos

Cloud Spanner admite tipos de datos simples, como los números enteros, y tipos más complejos, como ARRAY y STRUCT. En esta página, se proporciona una descripción general de cada tipo de datos, incluidos los valores permitidos.

El tamaño máximo del valor de una columna es de 10 MiB, que se aplica en los tipos escalares y de arreglo.

Tipos permitidos

Nombre del tipo ¿Tipo de columna válido? ¿Tipo de columna de claves válido? 1 ¿Tipo de SQL válido? Tamaño de almacenamiento 2
ARRAY No La suma del tamaño de sus elementos
BOOL 1 byte
BYTES La cantidad de bytes
DATE 4 bytes
FLOAT64 8 bytes
INT64 8 bytes
NUMERIC No Una función de la precisión y escalamiento del valor que se almacena. El valor 0 se almacena como 1 byte. El tamaño de almacenamiento de todos los demás valores varía entre 6 y 22 bytes.
STRING La cantidad de bytes en su codificación UTF-8
STRUCT No no No aplicable
TIMESTAMP 12 bytes

1 Claves primarias, índices secundarios y claves externas.
2 Además de los valores enumerados, cada celda tiene 8 bytes de sobrecarga de almacenamiento.

Propiedades de tipo de datos

Cuando se almacenan y consultan datos, es útil recordar las siguientes propiedades de tipo de datos:

Propiedad Descripción Se aplica a
Anulable NULL es un valor válido. Todos los tipos de datos.
Ordenable Se puede usar en una cláusula ORDER BY. Todos los tipos de datos, excepto los siguientes:
  • ARRAY
  • STRUCT
Agrupable En general, puede aparecer en una expresión después de
GROUP BY y DISTINCT.
Todos los tipos de datos, excepto los siguientes:
  • ARRAY
  • STRUCT
Comparable Los valores del mismo tipo se pueden comparar entre sí. Todos los tipos de datos, con las siguientes excepciones: no se admiten las comparaciones ARRAY.

Las comparaciones de igualdad para STRUCT se admiten campo por campo, en orden de campo. Los nombres de los campos se ignoran. No se admiten las comparaciones menor que y mayor que.

Todos los tipos que admiten comparaciones se pueden usar en una condición JOIN. Consulta los tipos de JOIN para obtener una explicación sobre las condiciones de unión.

Tipos numéricos

Los tipos numéricos incluyen tipos de números enteros, tipos de punto flotante y el tipo de datos NUMERIC.

Tipo de números enteros

Los números enteros son valores numéricos que no tienen componentes fraccionarios.

Name Rango
INT64 -9,223,372,036,854,775,808 a 9,223,372,036,854,775,807

Tipo NUMERIC

El tipo de datos NUMERIC es un valor numérico exacto con 38 dígitos de precisión y 9 dígitos decimales de escala. La precisión es el número de dígitos que contiene el número. La escala es cuántos de estos dígitos aparecen después del punto decimal.

Este tipo puede representar fracciones decimales exactamente y es adecuado para cálculos financieros.

Name Descripción Rango
NUMERIC Valores decimales con 38 dígitos decimales de precisión y 9 dígitos decimales de escala. -99999999999999999999999999999.999999999 a 99999999999999999999999999999.999999999
NUMERIC no es una columna de clave válida y no se puede usar en una clave primaria, una clave externa ni un índice.

Tipo punto flotante

Los valores de punto flotante son valores numéricos aproximados con componentes fraccionarios.

Name Descripción
FLOAT64 Valores decimales de doble precisión (aproximada).

Semántica de punto flotante

Cuando se trabaja con números de punto flotante, hay valores especiales no numéricos que se deben considerar: NaN y +/-inf

Aplica un formato a los valores especiales de punto flotante como Infinity, -Infinity y NaN cuando uses las API de REST y RPC de Cloud Spanner, como se documenta en TypeCode (REST) y TypeCode (RPC). Los literales +inf, -inf y nan no son compatibles con las API de REST y RPC de Cloud Spanner.

Los operadores aritméticos proporcionan el comportamiento IEEE-754 estándar a todos los valores de entrada finitos que producen salidas finitas y todas las operaciones para las cuales al menos una entrada es no finita.

Las llamadas de función y los operadores muestran un error de desbordamiento si la entrada es finita, pero la salida sería no finita. Si la entrada contiene valores no finitos, la salida puede ser no finita. En general, las funciones no ingresan NaN o +/-inf. Sin embargo, las funciones específicas como IEEE_DIVIDE pueden mostrar valores no finitos en entradas finitas. Todos estos casos se indican de manera explícita en las funciones matemáticas.

Ejemplos de funciones matemáticas
Término a la izquierda Operador Término a la derecha Muestra
Cualquier valor + NaN NaN
1.0 + +inf +inf
1.0 + -inf -inf
-inf + +inf NaN
Valor FLOAT64 máximo + Valor FLOAT64 máximo Error de desbordamiento
Valor FLOAT64 mínimo / 2.0 0.0
1.0 / 0.0 Error de división por cero

Los operadores de comparación proporcionan el comportamiento IEEE-754 estándar para la entrada de punto flotante.

Ejemplos de operadores de comparación
Término a la izquierda Operador Término a la derecha Muestra
NaN = Cualquier valor FALSE
NaN < Cualquier valor FALSE
Cualquier valor < NaN FALSE
-0.0 = 0.0 TRUE
-0.0 < 0.0 FALSE

Los valores de punto flotante se ordenan en este orden, de menor a mayor:

  1. NULL
  2. NaN: Todos los valores NaN se consideran iguales para el ordenamiento.
  3. -inf
  4. Números negativos
  5. 0 o -0: todos los valores cero se consideran iguales para el ordenamiento.
  6. Números positivos
  7. +inf

Los valores especiales de punto flotante se agrupan de esta manera, incluidos el agrupamiento realizado por una cláusula GROUP BY y el agrupamiento realizado por la palabra clave DISTINCT:

  • NULL
  • NaN: Todos los valores NaN se consideran iguales para el agrupamiento.
  • -inf
  • 0 o -0: Todos los valores cero se consideran iguales para el agrupamiento.
  • +inf

Tipo booleano

Nombre Descripción
BOOL Los valores booleanos están representados por las palabras clave TRUE y FALSE (no distinguen mayúsculas y minúsculas).

Tipo string

Nombre Descripción
STRING Datos de caracteres de longitud variable (Unicode).

Los valores STRING de entrada deben estar codificados en UTF-8 y los valores STRING de salida deben estar codificados en UTF-8. Las codificaciones alternativas como CESU-8 y UTF-8 modificada no se tratan como UTF-8 válidas.

Todas las funciones y operadores que actúan sobre los valores STRING operan en caracteres Unicode en lugar de bytes. Por ejemplo, las funciones como SUBSTR y LENGTH aplicadas a la entrada STRING cuentan el número de caracteres, no los bytes.

Cada carácter Unicode tiene un valor numérico denominado punto de código asignado. Los puntos de código más bajos se asignan a caracteres más bajos. Cuando se comparan los caracteres, los puntos de código determinan cuáles son los caracteres menores o mayores que otros.

La mayoría de las funciones en STRING también se definen en BYTES. La versión BYTES opera en bytes sin procesar en lugar de caracteres Unicode. STRING y BYTES son tipos diferentes que no se pueden usar de forma indistinta. No hay conversión de tipos implícita en ninguna dirección. La conversión de tipos explícita entre STRING y BYTES realiza la codificación y decodificación UTF-8. La conversión de tipos de BYTES a STRING muestra un error si los bytes no son UTF-8 válidos.

Tipo bytes

Nombre Descripción
BYTES Datos binarios de longitud variable.

STRING y BYTES son tipos diferentes que no se pueden usar de forma indistinta. La mayoría de las funciones en STRING también se definen en BYTES. La versión BYTES opera en bytes sin procesar en lugar de caracteres Unicode. Las conversiones entre STRING y BYTES hacen que los bytes se codifiquen mediante UTF-8.

Tipo fecha

Nombre Rango
DATE 0001-01-01 a 9999-12-31.

El tipo DATE representa una fecha lógica del calendario, independientemente de la zona horaria. Un valor DATE no representa un período específico de 24 horas. Más bien, un valor DATE dado representa un período diferente de 24 horas cuando se interpreta en diferentes zonas horarias. Este valor puede representar un día más corto o más largo durante las transiciones del horario de verano. Para representar un momento determinado absoluto, usa una marca de tiempo.

Formato canónico
'YYYY-[M]M-[D]D'
  • YYYY: Año de cuatro dígitos
  • [M]M: mes de uno o dos dígitos
  • [D]D: Día de uno o dos dígitos

Tipo marca de tiempo

Nombre Rango
TIMESTAMP De 0001-01-01 00:00:00 a 9999-12-31 23:59:59.999999 UTC.

Un objeto TIMESTAMP representa un punto absoluto en el tiempo, independientemente de cualquier zona horaria o convención como el horario de verano con precisión de nanosegundos.

  • Para representar una fecha, como podría aparecer en un calendario, usa un objeto DATE.
Formato canónico

Para las API de REST y RPC

Sigue las reglas de codificación y decodificación desde valores JSON como se describen en TypeCode (RPC) y TypeCode (REST). En particular, el valor de la marca de tiempo debe terminar con un literal “Z” en mayúscula para especificar la hora de Zulú (UTC-0).

Por ejemplo:

2014-09-27T12:30:00.45Z

Los valores de la marca de tiempo se deben expresar en la hora de Zulú y no pueden incluir un desplazamiento del UTC. Por ejemplo, la siguiente marca de tiempo no es compatible:

-- NOT SUPPORTED! TIMESTAMPS CANNOT INCLUDE A UTC OFFSET WHEN USED WITH THE REST AND RPC APIS
2014-09-27 12:30:00.45-8:00

Para bibliotecas cliente

Usa el formato de marcas de tiempo específico del lenguaje.

Para consultas de SQL

YYYY-[M]M-[D]D[( |T)[H]H:[M]M:[S]S[.DDDDDDDDD]][time zone]
  • YYYY: Año de cuatro dígitos
  • [M]M: mes de uno o dos dígitos
  • [D]D: día de uno o dos dígitos
  • ( |T): un espacio o un separador “T”
  • [H]H: hora de uno o dos dígitos (valores válidos de 00 a 23)
  • [M]M: minutos de uno o dos dígitos (valores válidos de 00 a 59)
  • [S]S: Segundos de uno o dos dígitos (valores válidos de 00 a 59)
  • [.DDDDDDDDD]: Hasta nueve dígitos fraccionales (con una precisión de nanosegundos)
  • [time zone]: string que representa la zona horaria Cuando no se especifica una zona horaria de forma explícita, se usa la zona horaria predeterminada, America/Los_Angeles. Consulta la sección de zonas horarias para obtener más detalles.

Zonas horarias

Las zonas horarias se usan cuando se analizan o se formatean las marcas de tiempo para fines de visualización. El valor de la marca de tiempo no almacena una zona horaria específica ni cambia cuando aplicas un desplazamiento de zona horaria.

Las zonas horarias se representan con strings en uno de estos dos formatos canónicos:

  • Desplazamiento del Horario Universal Coordinado (UTC) o la letra Z para UTC
  • Nombre de la zona horaria de la base de datos tz

Desplazamiento del Horario Universal Coordinado (UTC)

(+|-)H[H][:M[M]]
Z

Ejemplos

-08:00
-8:15
+3:00
+07:30
-7
Z

Cuando se usa este formato, no se permite ningún espacio entre la zona horaria y el resto de la marca de tiempo.

2014-09-27 12:30:00.45-8:00
2014-09-27T12:30:00.45Z

Nombre de zona horaria

continent/[region/]city

Los nombres de zonas horarias son de la base de datos tz. Si prefieres una referencia menos completa, pero más simple, consulta la lista de zonas horarias de la base de datos tz en Wikipedia.

Ejemplos

America/Los_Angeles
America/Argentina/Buenos_Aires

Cuando se usa un nombre de zona horaria, es obligatorio que haya un espacio entre el nombre y el resto de la marca de tiempo:

2014-09-27 12:30:00.45 America/Los_Angeles

Ten en cuenta que no todos los nombres de zona horaria son intercambiables, incluso si informan la misma hora durante una parte determinada del año. Por ejemplo, America/Los_Angeles representa la misma hora que UTC-7:00 durante el horario de verano, pero representa la misma hora que UTC-8:00 el resto del año.

Si no se especifica una zona horaria, se usa el valor predeterminado de la zona horaria.

Segundos bisiestos

Una marca de tiempo no es más que un desplazamiento de 1970-01-01 00:00:00 UTC, si se supone que hay exactamente 60 segundos por minuto. Los segundos bisiestos no se representan como parte de una marca de tiempo almacenada.

Si la entrada contiene valores que usan “:60” en el campo de segundos para representar un segundo bisiesto, ese segundo bisiesto no se conserva cuando se convierte en un valor de marca de tiempo. En su lugar, ese valor se interpreta como una marca de tiempo con “:00” en el campo de segundos del siguiente minuto.

Los segundos bisiestos no afectan los cálculos de marca de tiempo. Todos los cálculos de marca de tiempo se realizan mediante marcas de tiempo de estilo Unix, que no reflejan segundos bisiestos. Los segundos bisiestos solo son observables a través de funciones que miden el tiempo real. En estas funciones, es posible que un segundo de la marca de tiempo se omita o se repita cuando hay un segundo bisiesto.

Tipo Array

Nombre Descripción
ARRAY Lista ordenada de cero o más elementos de cualquier tipo que no sea ARRAY.

Un ARRAY es una lista ordenada de cero o más elementos de valores que no son ARRAY. No se permiten arreglos ARRAY de varios ARRAY. Las consultas que podrían producir un ARRAY de varios ARRAY mostrarán un error. En su lugar, se debe insertar un STRUCT entre los ARRAY mediante la construcción SELECT AS STRUCT.

Un ARRAY vacío y un ARRAY NULL son dos valores distintos. Los ARRAY pueden contener elementos NULL.

Cómo declarar un tipo ARRAY

ARRAY<T>

Los tipos ARRAY se declaran mediante los corchetes angulares (< y >). El tipo de elementos de un ARRAY puede ser arbitrariamente complejo, con la excepción de que un ARRAY no puede contener de forma directa otro ARRAY.

Ejemplos

Declaración del tipo Significado
ARRAY<INT64> ARRAY simple de números enteros de 64 bits.
ARRAY<STRUCT<INT64, INT64>> Un ARRAY de STRUCT, cada uno de los cuales contiene dos números enteros de 64 bits.
Nota: Las expresiones de SQL pueden construir ARRAY de valores STRUCT, pero estos no se admiten como tipos de columnas.
ARRAY<ARRAY<INT64>>
(no admitido)
Esta es una declaración de tipo no válida que se incluye aquí en caso de que busques crear un ARRAY de múltiples niveles. Los ARRAY no pueden contener ARRAY directamente. En su lugar, consulta el siguiente ejemplo.
ARRAY<STRUCT<ARRAY<INT64>>> Un ARRAY de varios ARRAY de números enteros de 64 bits. Observa que hay un STRUCT entre los dos ARRAY porque los ARRAY no pueden contener otros ARRAY directamente.
Nota: Las expresiones de SQL pueden construir ARRAY de valores STRUCT, pero estos no se admiten como tipos de columnas.

Tipo Struct

Consulta los detalles sobre el uso de STRUCT en las secciones sobre declaraciones SELECT y subconsultas en la página de la sintaxis de consulta.

Nombre Descripción
STRUCT Contenedor de campos ordenados, cada uno con un tipo (obligatorio) y un nombre de campo (opcional).

Cómo declarar un tipo STRUCT

STRUCT<T>

Los tipos STRUCT se declaran mediante los corchetes angulares (< y >). El tipo de elementos de un STRUCT puede ser arbitrariamente complejo.

Nota: Las expresiones de SQL pueden construir valores STRUCT, pero estos no se admiten como tipos de columnas.

Ejemplos

Declaración del tipo Significado
STRUCT<INT64> STRUCT simple con un único campo de número entero de 64 bits sin nombre.
STRUCT<x STRUCT<y INT64, z INT64>> Un STRUCT que contiene un STRUCT anidado llamado x. El STRUCT x tiene dos campos, y y z, que son números enteros de 64 bits.
STRUCT<inner_array ARRAY<INT64>> Un STRUCT que contiene un ARRAY llamado inner_array que retiene números enteros de 64 bits.

Construye un STRUCT

Sintaxis de la tupla

(expr1, expr2 [, ... ])

El tipo de salida es un tipo STRUCT anónimo con campos anónimos con tipos que coinciden con los tipos de las expresiones de entrada. Debe haber al menos dos expresiones especificadas. De lo contrario, esta sintaxis es indistinguible de una expresión encerrada entre paréntesis.

Ejemplos

Sintaxis Tipo de salida Notas
(x, x+y) STRUCT<?,?> Si se usan nombres de columna (strings sin comillas), el tipo de datos del campo STRUCT se deriva del tipo de datos de la columna. x yy son columnas, por lo que los tipos de datos de los campos STRUCT se derivan de los tipos de columna y el tipo de salida del operador de suma.

Esta sintaxis también se puede usar con la comparación STRUCT para expresiones de comparación mediante claves de varias partes, p. ej., en una cláusula WHERE:

WHERE (Key1,Key2) IN ( (12,34), (56,78) )

Sintaxis de struct sin tipo

STRUCT( expr1 [AS field_name] [, ... ])

Se permiten nombres de campo duplicados. Los campos sin nombre se consideran campos anónimos y no se puede hacer referencia a ellos por nombre. Los valores de STRUCT pueden ser NULL o pueden tener valores de campo NULL.

Ejemplos

Sintaxis Tipo de salida
STRUCT(1,2,3) STRUCT<int64,int64,int64>
STRUCT() STRUCT<>
STRUCT('abc') STRUCT<string>
STRUCT(1, t.str_col) STRUCT<int64, str_col string>
STRUCT(1 AS a, 'abc' AS b) STRUCT<a int64, b string>
STRUCT(str_col AS abc) STRUCT<abc string>

Sintaxis de struct escrita

STRUCT<[field_name] field_type, ...>( expr1 [, ... ])

La sintaxis escrita permite construir STRUCT con un tipo de datos STRUCT explícito. El tipo de salida es exactamente el field_type proporcionado. La expresión de entrada se coerciona a field_type si los dos tipos no son iguales y se genera un error si los tipos no son compatibles. AS alias no está permitido en las expresiones de entrada. El número de expresiones debe coincidir con el número de campos del tipo y los tipos de expresión deben ser coercibles o coercibles por literal para los tipos de campo.

Ejemplos

Sintaxis Tipo de salida
STRUCT<int64>(5) STRUCT<int64>
STRUCT<date>("2011-05-05") STRUCT<date>
STRUCT<x int64, y string>(1, t.str_col) STRUCT<x int64, y string>
STRUCT<int64>(int_col) STRUCT<int64>
STRUCT<x int64>(5 AS x) Error: la sintaxis escrita no permite AS

Comparaciones limitadas para STRUCT

Las STRUCT se pueden comparar directamente mediante operadores de igualdad:

  • Igual (=)
  • No es igual (!= o <>)
  • [NOT] IN

Sin embargo, ten en cuenta que estas comparaciones de igualdad directas cotejan los campos de STRUCT por pares en el orden ordinal, sin fijarse en los nombres de campo. Si, en cambio, deseas comparar campos con nombres idénticos de una STRUCT, puedes cotejar los campos individuales directamente.