在Postgres 9.3+中将JSON转换为HSTORE?

时间:2015-02-04 07:39:28

标签: json postgresql database-migration hstore

我已阅读过文档,似乎没有明显的方法可以执行ALTER TABLE ... ALTER COLUMN ... USING语句直接将json类型列转换为hstore类型。没有可用的功能(我知道)可以执行演员表。

我的下一个最佳选择是创建一个hstore类型的新列,使用一些外部工具将我的JSON数据复制到该新列,删除旧json列并重命名新{ {1}}列为旧列的名称。

有更好的方法吗?

到目前为止我所拥有的是:

hstore
$ CREATE TABLE blah (unstructured_data JSON);

$ ALTER TABLE blah ALTER COLUMN unstructured_data 
       TYPE hstore USING CAST(unstructured_data AS hstore);

2 个答案:

答案 0 :(得分:9)

不幸的是,PostgreSQL不允许USING ALTER TABLE ... SET DATA TYPE ...子句中的所有类型的表达式(不允许使用f.ex.子查询)。

但是,你可以编写一个函数来克服这个问题,你只需要决定如何处理高级类型(在对象的值中),比如数组和数组。对象。这是一个示例,它只是将它们转换为字符串:

CREATE OR REPLACE FUNCTION my_json_to_hstore(json)
  RETURNS hstore
  IMMUTABLE
  STRICT
  LANGUAGE sql
AS $func$
  SELECT hstore(array_agg(key), array_agg(value))
  FROM   json_each_text($1)
$func$;

之后,您可以在ALTER TABLE中使用此功能,例如:

ALTER TABLE blah
  ALTER COLUMN unstructured_data
  SET DATA TYPE hstore USING my_json_to_hstore(unstructured_data);

答案 1 :(得分:1)

存在重复键的“陷阱”-由jsonhstore输入均允许,但不幸的是解决方式不同(!)。考虑以下示例值:

json '{"double_key":"key1","foo":null,"double_key":"key2"}'

json中,“ double_key实际上是'key2'The manual:

  

由于json类型存储输入文本的精确副本,因此它将   保留标记之间语义上无关紧要的空白,例如   以及JSON对象中键的顺序。另外,如果是JSON对象   值中包含多次相同的键,所有   键/值对被保留。 (处理功能将最后一个值视为有效值。)

强调粗体。

但是在hstore中,对于相同顺序的键/值对,'double_key' 可能 有效地是'key1'The manual:

  

hstore中的每个键都是唯一的。如果您声明hstore为   重复的密钥,只有一个将存储在hstore中,并且不能保证保留哪些密钥

通常,是键的 first 实例,但这是可能会更改的实现细节。

始终保留有效的操作价值的简单快捷选项:转换前强制转换为jsonbThe manual again:

  

[...] jsonb不保留空格,不保留   对象键的顺序,并且不保留重复的对象键。   如果在输入中指定了重复的键,则仅保留最后一个值。

修改@pozs's conversion function

CREATE OR REPLACE FUNCTION json2hstore(json)
  RETURNS hstore AS
$func$
  SELECT hstore(array_agg(key), array_agg(value))
  FROM   jsonb_each_text($1::jsonb)  -- !
$func$ LANGUAGE sql IMMUTABLE STRICT;

需要Postgres 9.4 或更高版本。 Postgres 9.3具有json类型,但还没有jsonb类型。 PL / v8中的无操作可能是替代方法,例如@jpmc mentioned