2012-02-16 11 views
17

De acuerdo con la documentación de Postgres, se agrega una clave a una columna hstore de la siguiente manera:Adición de una clave a una columna vacía hstore

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

Pero parece que funciona sólo si el campo hstore no está vacío. Por ejemplo:

postgres=# create table htest (t text, h hstore); 
CREATE TABLE 
postgres=# insert into htest (t) VALUES ('key'); 
INSERT 0 1 
postgres=# update htest set h = h || ('foo'=>'bar') where t='key'; 
UPDATE 1 
postgres=# select * from htest; 
    t | h 
-----+--- 
key | 
(1 row) 

La actualización fue correcta, pero el hstore no se actualizó. Sin embargo:

postgres=# update htest set h = ('foo'=>'bar') where t='key'; 
UPDATE 1 
postgres=# select * from htest; 
    t |  h  
-----+-------------- 
key | "foo"=>"bar" 
(1 row) 

postgres=# update htest set h = h || ('bar'=>'foo') where t='key'; 
UPDATE 1 
postgres=# select * from htest; 
    t |    h    
-----+---------------------------- 
key | "bar"=>"foo", "foo"=>"bar" 
(1 row) 

¿Hay una manera de agregar una clave atómicamente a un hstore sin comprobar previamente si el hstore está vacía?

Respuesta

16

Creo que el problema aquí es que el hstore que tiene es nulo, nulo O algún almacén es nulo.

La mejor solución que tengo, que probablemente no es la mejor solución, es hacer la tabla con un almacén vacío predeterminado en lugar de permitir nulo. A continuación, sus ejemplos funcionan como le gustaría:

postgres=# create table htest (t text, h hstore default hstore(array[]::varchar[])); 
CREATE TABLE 
postgres=# insert into htest (t) values ('key'); 
INSERT 0 1 
postgres=# update htest set h = h || ('foo'=>'bar') where t='key'; 
UPDATE 1 
postgres=# select * from htest; 
    t |  h  
-----+-------------- 
key | "foo"=>"bar" 
(1 row) 

que por desgracia no ven una forma más limpia para crear un vacío que hstore hstore(array[]::varchar[]) pero eso no quiere decir que no hay una mejor manera. Se podría incorporar esto en su actualización de hstore de delante de este modo:

update htest set h = coalesce(h, hstore(array[]::varchar[])) || ('foo'=>'bar') where t='key'; 

De esta manera no es necesario volver a crear la tabla. Aunque me parece bastante asqueroso. Espero que esto ayude.

+0

Gracias! Me di cuenta de que mi tienda era nula, pero no sabía que eso fuera diferente de una tienda vacía. – janr

+0

¡Buenas cosas, gracias Daniel! –

+2

Puede ser una nota útil para alguien en el futuro. Estoy usando 8.4 y creo el hstore vacío con hstore ('') en lugar de hstore (array [] :: varchar []) – trex005

6

Para evitar esto, necesita asegurarse de que hstore se crea como vacío y no nulo. Se puede añadir una hstore vacío a una tabla existente:

ALTER TABLE htest ADD h HSTORE NOT NULL DEFAULT ''; 

O bien, puede alterar su hstore existente para vaciar:

ALTER TABLE htest ALTER COLUMN h SET NOT NULL; 
ALTER TABLE htest ALTER COLUMN h SET DEFAULT ''; 

Tenga en cuenta que los valores que salen no pueden ser nulos cuando se establece la columna ' NO NULO'.

6

¿qué tal:

UPDATE htest SET h = COALESCE(h, '') || ('foo'=>'bar') WHERE t='key'; 
4

Para Postgres versión > 9.1:

UPDATE htest SET h = COALESCE(h, hstore('')) || hstore('foo', 'bar') WHERE t='key'; 
Cuestiones relacionadas