F.17. hstore — tipo de datos clave/valor hstore #

F.17.1. Representación externa de hstore
F.17.2. Operadores y funciones de hstore
F.17.3. Índices
F.17.4. Ejemplos
F.17.5. Estadísticas
F.17.6. Compatibilidad
F.17.7. Transformaciones
F.17.8. Autores

Este módulo implementa el tipo de datos hstore para almacenar conjuntos de pares clave/valor dentro de un único valor de PostgreSQL. Esto puede ser útil en varios escenarios, como filas con muchos atributos que rara vez se examinan, o datos semiestructurados. Las claves y los valores son simplemente cadenas de texto.

Este módulo se considera trusted (confiable), es decir, puede ser instalado por no superusuarios que tengan el privilegio CREATE en la base de datos actual.

F.17.1. Representación externa de hstore #

La representación en texto de un hstore, utilizada para la entrada y la salida, incluye cero o más pares clave => valor separados por comas. Algunos ejemplos:

k => v
foo => bar, baz => whatever
"1-a" => "anything at all"

El orden de los pares no es significativo (y puede que no se reproduzca en la salida). Los espacios en blanco entre los pares o alrededor del signo => se ignoran. Escribe entre comillas dobles las claves y valores que incluyan espacios en blanco, comas, signos = o >. Para incluir una comilla doble o una barra invertida en una clave o valor, escápala con una barra invertida.

Cada clave en un hstore es única. Si declaras un hstore con claves duplicadas, solo una se almacenará en el hstore y no hay garantía de cuál se mantendrá:

SELECT 'a=>1,a=>2'::hstore;
  hstore
----------
 "a"=>"1"

Un valor (pero no una clave) puede ser un NULL de SQL. Por ejemplo:

key => NULL

La palabra clave NULL no distingue entre mayúsculas y minúsculas. Escribe entre comillas dobles NULL para tratarlo como la cadena de texto ordinaria NULL.

Note

Ten en cuenta que el formato de texto de hstore, cuando se usa para la entrada, se aplica antes de cualquier entrecomillado o escape requerido. Si estás pasando un literal de hstore a través de un parámetro, no se necesita ningún procesamiento adicional. Pero si lo estás pasando como una constante literal entrecomillada, entonces cualquier carácter de comilla simple y (dependiendo de la configuración del parámetro de configuración standard_conforming_strings) los caracteres de barra invertida deben escaparse correctamente. Consulta la Section 4.1.2.1 para obtener más información sobre el manejo de constantes de cadena.

En la salida, las comillas dobles siempre rodean a las claves y a los valores, incluso cuando no es estrictamente necesario.

F.17.2. Operadores y funciones de hstore #

Los operadores proporcionados por el módulo hstore se muestran en la Table F.6, y las funciones en la Table F.7.

Table F.6. Operadores de hstore

Operador

Descripción

Ejemplo(s)

hstore -> texttext

Devuelve el valor asociado a la clave dada, o NULL si no está presente.

'a=>x, b=>y'::hstore -> 'a'x

hstore -> text[]text[]

Devuelve los valores asociados a las claves dadas, o NULL si no están presentes.

'a=>x, b=>y, c=>z'::hstore -> ARRAY['c','a']{"z","x"}

hstore || hstorehstore

Concatena dos hstores.

'a=>b, c=>d'::hstore || 'c=>x, d=>q'::hstore"a"=>"b", "c"=>"x", "d"=>"q"

hstore ? textboolean

¿Contiene el hstore la clave?

'a=>1'::hstore ? 'a't

hstore ?& text[]boolean

¿Contiene el hstore todas las claves especificadas?

'a=>1,b=>2'::hstore ?& ARRAY['a','b']t

hstore ?| text[]boolean

¿Contiene el hstore alguna de las claves especificadas?

'a=>1,b=>2'::hstore ?| ARRAY['b','c']t

hstore @> hstoreboolean

¿Contiene el operando izquierdo al derecho?

'a=>b, b=>1, c=>NULL'::hstore @> 'b=>1't

hstore <@ hstoreboolean

¿Está el operando izquierdo contenido en el derecho?

'a=>c'::hstore <@ 'a=>b, b=>1, c=>NULL'f

hstore - texthstore

Elimina la clave del operando izquierdo.

'a=>1, b=>2, c=>3'::hstore - 'b'::text"a"=>"1", "c"=>"3"

hstore - text[]hstore

Elimina las claves del operando izquierdo.

'a=>1, b=>2, c=>3'::hstore - ARRAY['a','b']"c"=>"3"

hstore - hstorehstore

Elimina del operando izquierdo los pares que coincidan con los del operando derecho.

'a=>1, b=>2, c=>3'::hstore - 'a=>4, b=>2'::hstore"a"=>"1", "c"=>"3"

anyelement #= hstoreanyelement

Reemplaza los campos en el operando izquierdo (que debe ser un tipo compuesto) con los valores coincidentes del hstore.

ROW(1,3) #= 'f1=>11'::hstore(11,3)

%% hstoretext[]

Convierte el hstore en un array de claves y valores alternados.

%% 'a=>foo, b=>bar'::hstore{a,foo,b,bar}

%# hstoretext[]

Convierte el hstore en un array bidimensional de claves/valores.

%# 'a=>foo, b=>bar'::hstore{{a,foo},{b,bar}}


Table F.7. Funciones de hstore

Función

Descripción

Ejemplo(s)

hstore ( record ) → hstore

Construye un hstore a partir de un registro o fila.

hstore(ROW(1,2))"f1"=>"1", "f2"=>"2"

hstore ( text[] ) → hstore

Construye un hstore a partir de un array, que puede ser un array de claves/valores o un array bidimensional.

hstore(ARRAY['a','1','b','2'])"a"=>"1", "b"=>"2"

hstore(ARRAY[['c','3'],['d','4']])"c"=>"3", "d"=>"4"

hstore ( text[], text[] ) → hstore

Construye un hstore a partir de arrays de claves y valores separados.

hstore(ARRAY['a','b'], ARRAY['1','2'])"a"=>"1", "b"=>"2"

hstore ( text, text ) → hstore

Crea un hstore de un solo elemento.

hstore('a', 'b')"a"=>"b"

akeys ( hstore ) → text[]

Extrae las claves de un hstore como un array.

akeys('a=>1,b=>2'){a,b}

skeys ( hstore ) → setof text

Extrae las claves de un hstore como un conjunto.

skeys('a=>1,b=>2')

a
b

avals ( hstore ) → text[]

Extrae los valores de un hstore como un array.

avals('a=>1,b=>2'){1,2}

svals ( hstore ) → setof text

Extrae los valores de un hstore como un conjunto.

svals('a=>1,b=>2')

1
2

hstore_to_array ( hstore ) → text[]

Extrae las claves y valores de un hstore como un array de claves y valores alternados.

hstore_to_array('a=>1,b=>2'){a,1,b,2}

hstore_to_matrix ( hstore ) → text[]

Extrae las claves y valores de un hstore como un array bidimensional.

hstore_to_matrix('a=>1,b=>2'){{a,1},{b,2}}

hstore_to_json ( hstore ) → json

Convierte un hstore en un valor de tipo json, convirtiendo todos los valores no nulos en cadenas JSON.

Esta función se utiliza implícitamente cuando un valor de tipo hstore es convertido a json.

hstore_to_json('"a key"=>1, b=>t, c=>null, d=>12345, e=>012345, f=>1.234, g=>2.345e+4'){"a key": "1", "b": "t", "c": null, "d": "12345", "e": "012345", "f": "1.234", "g": "2.345e+4"}

hstore_to_jsonb ( hstore ) → jsonb

Convierte un hstore en un valor de tipo jsonb, convirtiendo todos los valores no nulos en cadenas JSON.

Esta función se utiliza implícitamente cuando un valor de tipo hstore es convertido a jsonb.

hstore_to_jsonb('"a key"=>1, b=>t, c=>null, d=>12345, e=>012345, f=>1.234, g=>2.345e+4'){"a key": "1", "b": "t", "c": null, "d": "12345", "e": "012345", "f": "1.234", "g": "2.345e+4"}

hstore_to_json_loose ( hstore ) → json

Convierte un hstore en un valor de tipo json, pero intenta distinguir los valores numéricos y booleanos para que no lleven comillas en el JSON.

hstore_to_json_loose('"a key"=>1, b=>t, c=>null, d=>12345, e=>012345, f=>1.234, g=>2.345e+4'){"a key": 1, "b": true, "c": null, "d": 12345, "e": "012345", "f": 1.234, "g": 2.345e+4}

hstore_to_jsonb_loose ( hstore ) → jsonb

Convierte un hstore en un valor de tipo jsonb, pero intenta distinguir los valores numéricos y booleanos para que no lleven comillas en el JSON.

hstore_to_jsonb_loose('"a key"=>1, b=>t, c=>null, d=>12345, e=>012345, f=>1.234, g=>2.345e+4'){"a key": 1, "b": true, "c": null, "d": 12345, "e": "012345", "f": 1.234, "g": 2.345e+4}

slice ( hstore, text[] ) → hstore

Extrae un subconjunto de un hstore que contiene únicamente las claves especificadas.

slice('a=>1,b=>2,c=>3'::hstore, ARRAY['b','c','x'])"b"=>"2", "c"=>"3"

each ( hstore ) → setof record ( key text, value text )

Extrae las claves y valores de un hstore como un conjunto de registros.

select * from each('a=>1,b=>2')

 key | value
-----+-------
 a   | 1
 b   | 2

exist ( hstore, text ) → boolean

¿Contiene el hstore la clave?

exist('a=>1', 'a')t

defined ( hstore, text ) → boolean

¿Contiene el hstore un valor no nulo (NULL) para la clave?

defined('a=>NULL', 'a')f

delete ( hstore, text ) → hstore

Elimina el par con la clave coincidente.

delete('a=>1,b=>2', 'b')"a"=>"1"

delete ( hstore, text[] ) → hstore

Elimina los pares con las claves coincidentes.

delete('a=>1,b=>2,c=>3', ARRAY['a','b'])"c"=>"3"

delete ( hstore, hstore ) → hstore

Elimina los pares que coincidan con los del segundo argumento.

delete('a=>1,b=>2', 'a=>4,b=>2'::hstore)"a"=>"1"

populate_record ( anyelement, hstore ) → anyelement

Reemplaza los campos en el operando izquierdo (que debe ser un tipo compuesto) con los valores coincidentes del hstore.

populate_record(ROW(1,2), 'f1=>42'::hstore)(42,2)


Además de estos operadores y funciones, se pueden usar subíndices con los valores del tipo hstore, permitiendo que actúen como arrays asociativos. Solo se puede especificar un único subíndice de tipo text; este se interpreta como una clave y se obtiene o almacena el valor correspondiente. Por ejemplo,

CREATE TABLE mytable (h hstore);
INSERT INTO mytable VALUES ('a=>b, c=>d');
SELECT h['a'] FROM mytable;
 h
---
 b
(1 row)

UPDATE mytable SET h['c'] = 'new';
SELECT h FROM mytable;
          h
----------------------
 "a"=>"b", "c"=>"new"
(1 row)

Una obtención mediante subíndices devuelve NULL si el subíndice es NULL o si esa clave no existe en el hstore. (Por lo tanto, la obtención mediante subíndices no es muy diferente del operador ->). Una actualización mediante subíndices falla si el subíndice es NULL; de lo contrario, reemplaza el valor de esa clave, añadiendo una entrada al hstore si la clave aún no existe.

F.17.3. Índices #

hstore tiene soporte para índices GiST y GIN para los operadores @>, ?, ?& y ?|. Por ejemplo:

CREATE INDEX hidx ON testhstore USING GIST (h);

CREATE INDEX hidx ON testhstore USING GIN (h);

La clase de operadores GiST gist_hstore_ops aproxima un conjunto de pares clave/valor como una firma de mapa de bits. Su parámetro entero opcional siglen determina la longitud de la firma en bytes. La longitud por defecto es de 16 bytes. Los valores válidos de la longitud de la firma están entre 1 y 2024 bytes. Las firmas más largas permiten una búsqueda más precisa (escaneando una fracción menor del índice y menos páginas del heap), a costa de un tamaño de índice mayor.

Ejemplo de creación de este índice con una longitud de firma de 32 bytes:

CREATE INDEX hidx ON testhstore USING GIST (h gist_hstore_ops(siglen=32));

hstore también admite índices btree o hash para el operador =. Esto permite que las columnas de tipo hstore se declaren UNIQUE, o que se utilicen en expresiones GROUP BY, ORDER BY o DISTINCT. El orden de clasificación para los valores hstore no es especialmente útil, pero estos índices pueden ser de utilidad para búsquedas de equivalencia. Crea índices para comparaciones de tipo = de la siguiente manera:

CREATE INDEX hidx ON testhstore USING BTREE (h);

CREATE INDEX hidx ON testhstore USING HASH (h);

F.17.4. Ejemplos #

Añadir una clave o actualizar una clave existente con un nuevo valor:

UPDATE tab SET h['c'] = '3';

Otra forma de hacer lo mismo es:

UPDATE tab SET h = h || hstore('c', '3');

Si se van a añadir o cambiar varias claves en una sola operación, el enfoque de concatenación es más eficiente que el uso de subíndices:

UPDATE tab SET h = h || hstore(array['q', 'w'], array['11', '12']);

Eliminar una clave:

UPDATE tab SET h = delete(h, 'k1');

Convertir un registro (record) en un hstore:

CREATE TABLE test (col1 integer, col2 text, col3 text);
INSERT INTO test VALUES (123, 'foo', 'bar');

SELECT hstore(t) FROM test AS t;
                   hstore
---------------------------------------------
 "col1"=>"123", "col2"=>"foo", "col3"=>"bar"
(1 row)

Convertir un hstore en un tipo de registro (record) predefinido:

CREATE TABLE test (col1 integer, col2 text, col3 text);

SELECT * FROM populate_record(null::test,
                              '"col1"=>"456", "col2"=>"zzz"');
 col1 | col2 | col3
------+------+------
  456 | zzz  |
(1 row)

Modificar un registro existente utilizando los valores de un hstore:

CREATE TABLE test (col1 integer, col2 text, col3 text);
INSERT INTO test VALUES (123, 'foo', 'bar');

SELECT (r).* FROM (SELECT t #= '"col3"=>"baz"' AS r FROM test t) s;
 col1 | col2 | col3
------+------+------
  123 | foo  | baz
(1 row)

F.17.5. Estadísticas #

El tipo hstore, debido a su flexibilidad intrínseca, puede contener muchas claves diferentes. Verificar las claves válidas es tarea de la aplicación. Los siguientes ejemplos muestran varias técnicas para verificar claves y obtener estadísticas.

Ejemplo sencillo:

SELECT * FROM each('aaa=>bq, b=>NULL, ""=>1');

Usar una tabla:

CREATE TABLE stat AS SELECT (each(h)).key, (each(h)).value FROM testhstore;

Estadísticas en tiempo real (online):

SELECT key, count(*) FROM
  (SELECT (each(h)).key FROM testhstore) AS stat
  GROUP BY key
  ORDER BY count DESC, key;
    key    | count
-----------+-------
  line     |   883
  query    |   207
  pos      |   203
  node     |   202
  space    |   197
  status   |   195
  public   |   194
  title    |   190
  org      |   189
.................

F.17.6. Compatibilidad #

A partir de PostgreSQL 9.0, hstore utiliza una representación interna diferente a la de las versiones anteriores. Esto no presenta ningún obstáculo para las actualizaciones mediante volcado/restauración (dump/restore), ya que la representación en texto (utilizada en el volcado) no ha cambiado.

En caso de una actualización binaria (binary upgrade), la compatibilidad hacia arriba se mantiene haciendo que el nuevo código reconozca los datos con el formato antiguo. Esto supondrá una ligera penalización en el rendimiento al procesar datos que aún no hayan sido modificados por el nuevo código. Es posible forzar la actualización de todos los valores de una columna de una tabla mediante una instrucción UPDATE de la siguiente manera:

UPDATE tablename SET hstorecol = hstorecol || '';

Otra forma de hacerlo es:

UPDATE tablename SET hstorecol = hstorecol || '';

Otra forma de hacerlo es:

ALTER TABLE tablename ALTER hstorecol TYPE hstore USING hstorecol || '';

El método ALTER TABLE requiere un bloqueo ACCESS EXCLUSIVE en la tabla, pero no produce un crecimiento innecesario (bloat) de la tabla con versiones antiguas de las filas.

F.17.7. Transformaciones #

Existen extensiones adicionales que implementan transformaciones para el tipo hstore para los lenguajes PL/Perl y PL/Python. Las extensiones para PL/Perl se llaman hstore_plperl y hstore_plperlu, para PL/Perl confiable y no confiable respectivamente. Si instalas estas transformaciones y las especificas al crear una función, los valores hstore se mapearán a hashes de Perl. Las extensiones para PL/Python se llaman hstore_plpython3u. Si la utilizas, los valores de tipo hstore se mapearán a diccionarios de Python.

F.17.8. Autores #

Oleg Bartunov , Moscú, Universidad de Moscú, Rusia

Teodor Sigaev , Moscú, Delta-Soft Ltd., Rusia

Mejoras adicionales por Andrew Gierth , Reino Unido