在 Postgres 9.3+ 中将 JSON 投射到 HSTORE?
Cast JSON to HSTORE in Postgres 9.3+?
我已阅读文档,似乎没有明确的方法来执行 ALTER TABLE ... ALTER COLUMN ... USING
语句以将 json
类型的列直接转换为 hstore
类型。没有可用的功能(据我所知)来执行转换。
我的下一个最佳选择是创建一个类型为 hstore
的新列,使用一些外部工具将我的 JSON 数据复制到该新列,删除旧的 json
列并将新 hstore
列重命名为旧列的名称。
有没有更好的方法?
我目前拥有的是:
$ CREATE TABLE blah (unstructured_data JSON);
$ ALTER TABLE blah ALTER COLUMN unstructured_data
TYPE hstore USING CAST(unstructured_data AS hstore);
ERROR: cannot cast type json to hstore
不幸的是,PostgreSQL 不允许在 ALTER TABLE ... SET DATA TYPE ...
的 USING
子句中使用所有类型的表达式(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()
$func$;
之后,您可以在 ALTER TABLE
中使用它,例如:
ALTER TABLE blah
ALTER COLUMN unstructured_data
SET DATA TYPE hstore USING my_json_to_hstore(unstructured_data);
重复键 有 "trap" - json
和 hstore
输入都允许,但不幸的是解决方式不同(!)。考虑这个示例值:
json '{"double_key":"key1","foo":null,"double_key":"key2"}'
在json
中,'double_key实际上是'key2'。 The manual:
Because the json
type stores an exact copy of the input text, it will
preserve semantically-insignificant white space between tokens, as
well as the order of keys within JSON objects. Also, if a JSON object
within the value contains the same key more than once, all the
key/value pairs are kept. (The processing functions consider the last value as the operative one.)
大胆强调我的。
在hstore
中,然而,对于相同顺序的key/value对,'double_key'可能 实际上是 'key1'。 The manual:
Each key in an hstore
is unique. If you declare an hstore
with
duplicate keys, only one will be stored in the hstore
and there is no guarantee as to which will be kept:
通常,第一个 键实例,但这是一个可能会更改的实现细节。
始终保留有效的操作值的简单而快速的选项:转换前转换为jsonb
。 The manual again:
[...] jsonb
does not preserve white space, does not preserve
the order of object keys, and does not keep duplicate object keys.
If duplicate keys are specified in the input, only the last value is kept.
修改:
CREATE OR REPLACE FUNCTION json2hstore(json)
RETURNS hstore AS
$func$
SELECT hstore(array_agg(key), array_agg(value))
FROM jsonb_each_text(::jsonb) -- !
$func$ LANGUAGE sql IMMUTABLE STRICT;
需要 Postgres 9.4 或更高版本。 Postgres 9.3 有 json
类型,但还没有 jsonb
。 PL/v8 中的空操作可能是替代方案,例如 .
我已阅读文档,似乎没有明确的方法来执行 ALTER TABLE ... ALTER COLUMN ... USING
语句以将 json
类型的列直接转换为 hstore
类型。没有可用的功能(据我所知)来执行转换。
我的下一个最佳选择是创建一个类型为 hstore
的新列,使用一些外部工具将我的 JSON 数据复制到该新列,删除旧的 json
列并将新 hstore
列重命名为旧列的名称。
有没有更好的方法?
我目前拥有的是:
$ CREATE TABLE blah (unstructured_data JSON);
$ ALTER TABLE blah ALTER COLUMN unstructured_data
TYPE hstore USING CAST(unstructured_data AS hstore);
ERROR: cannot cast type json to hstore
不幸的是,PostgreSQL 不允许在 ALTER TABLE ... SET DATA TYPE ...
的 USING
子句中使用所有类型的表达式(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()
$func$;
之后,您可以在 ALTER TABLE
中使用它,例如:
ALTER TABLE blah
ALTER COLUMN unstructured_data
SET DATA TYPE hstore USING my_json_to_hstore(unstructured_data);
重复键 有 "trap" - json
和 hstore
输入都允许,但不幸的是解决方式不同(!)。考虑这个示例值:
json '{"double_key":"key1","foo":null,"double_key":"key2"}'
在json
中,'double_key实际上是'key2'。 The manual:
Because the
json
type stores an exact copy of the input text, it will preserve semantically-insignificant white space between tokens, as well as the order of keys within JSON objects. Also, if a JSON object within the value contains the same key more than once, all the key/value pairs are kept. (The processing functions consider the last value as the operative one.)
大胆强调我的。
在hstore
中,然而,对于相同顺序的key/value对,'double_key'可能 实际上是 'key1'。 The manual:
Each key in an
hstore
is unique. If you declare anhstore
with duplicate keys, only one will be stored in thehstore
and there is no guarantee as to which will be kept:
通常,第一个 键实例,但这是一个可能会更改的实现细节。
始终保留有效的操作值的简单而快速的选项:转换前转换为jsonb
。 The manual again:
[...]
jsonb
does not preserve white space, does not preserve the order of object keys, and does not keep duplicate object keys. If duplicate keys are specified in the input, only the last value is kept.
修改
CREATE OR REPLACE FUNCTION json2hstore(json)
RETURNS hstore AS
$func$
SELECT hstore(array_agg(key), array_agg(value))
FROM jsonb_each_text(::jsonb) -- !
$func$ LANGUAGE sql IMMUTABLE STRICT;
需要 Postgres 9.4 或更高版本。 Postgres 9.3 有 json
类型,但还没有 jsonb
。 PL/v8 中的空操作可能是替代方案,例如