【问题标题】:Change column type from JSONB to JSON将列类型从 JSONB 更改为 JSON
【发布时间】:2021-11-30 12:57:47
【问题描述】:

我知道大多数用户都在寻找 jsonb 类型,其中检索值比 json 类型快得多。尽管如此,我仍然需要键值中的顺序,到目前为止,我相信实现这一点的最佳方法是将我的列类型迁移到 json。 我尝试了以下方法:

ALTER TABLE table_name
ALTER COLUMN jsonb_colum TYPE json

和

ALTER TABLE table_name
ALTER COLUMN jsonb_colum TYPE json
USING jsonb_colum::json

在这两种情况下,我都会收到此错误:

ERROR: Operator class "jsonb_path_ops" does not accept data type json.

我还尝试使用USING 子句和如下表达式:

ALTER TABLE table_name
ALTER COLUMN jsonb_column TYPE json
USING jsonb_column::to_json(jsonb_colum)

但也没有运气,得到以下错误:

ERROR: Type "to_json" does not exist

有什么办法可以让我的愿望成真吗?

我正在使用PostgreSQL 13.3 (Debian 13.3-1.pgdg100+1) 64-bit

【问题讨论】:

  • 只做:ALTER TABLE table_name ALTER COLUMN jsonb_colum TYPE json,没有USING。
  • 刚刚更新了我的问题,这样做给了我同样的错误@AdrianKlaver
  • 什么版本的 Postgres?在您的问题中添加表格的定义。如果你这样做select jsonb_column::json from table_name会发生什么?
  • 您在该列上有索引吗?您需要先删除所有这些
  • 回复@AdrianKlaver:我正在使用PostgreSQL 13.3,如果我执行你给出的语句,它会起作用!这对我来说似乎很奇怪。

标签: json postgresql ddl jsonb


【解决方案1】:

jsonb_path_ops is an operator class 用于 GIN 索引。喜欢:

CREATE INDEX foo ON table_name USING gin (jsonb_column jsonb_path_ops);

这样的索引的存在会准确地产生您的第一条错误消息。您需要先删除任何此类索引,然后才能更改列类型 - 使用您的第一个有效的 ALTER TABLE 语句。

然而,这种索引的存在表明需要支持以下jsonb 运算符中的一个或多个:@>、@?、@@。如果是这样,请考虑在转换为 json 后创建一个 expression index 以替换旧的。喜欢:

CREATE INDEX foo ON table_name USING gin ((now_json_column::jsonb) jsonb_path_ops);

(需要括号。)
然后仍然支持这样的查询(即使成本稍高):

SELECT * FROM table_name
WHERE  now_json_column::jsonb @> '{"some_key": "some_val"}';

相关:

另外,请注意json 缺少基本的等式和不等式运算符。见:

【讨论】:

    【解决方案2】:

    可以使用查询从现有的 jsonb 列中更新新创建的 json 格式列,并按所需顺序选择键。下面是一个示例表、数据集和更新查询。

    create table crayons (
    id serial,
    color_json json,
    color_jsonb jsonb,
    primary key (id))
    
    ugautil=> \d crayons
    Table "public.crayons"
    Column    |  Type   | Collation | Nullable |               Default             
    -------------+---------+-----------+----------+-----------------------------------
    id          | integer |           | not null | nextval('crayons_id_seq'::regclass)
    color_json  | json    |           |          | 
    color_jsonb | jsonb   |           |          | 
    Indexes:
    "crayons_pkey" PRIMARY KEY, btree (id)
    

    color_json 列将保留与原始数据中相同的文本 文件。 color_jsonb 列不会保留键顺序, 重复的键、额外的空格等。

    前5行数据:

    ugautil=> select color_json from crayons order by id limit 5;
    -----------------------------------------------------------
    {"hex":"#EFDECD","name":"Almond","rgb":"(239, 222, 205)"}
    {"hex":"#CD9575","name":"Antique Brass","rgb":"(205, 149, 117)"}
    {"hex":"#FDD9B5","name":"Apricot","rgb":"(253, 217, 181)"}
    {"hex":"#78DBE2","name":"Aquamarine","rgb":"(120, 219, 226)"}
    {"hex":"#87A96B","name":"Asparagus","rgb":"(135, 169, 107)"}
    

    当我们从 jsonb 列中选择相同的数据时,请注意它改变了键顺序。 名称在 rgb 之后

    ugautil=> select color_jsonb from crayons order by id limit 5;
    -------------------------------------------------------------
    {"hex": "#EFDECD", "rgb": "(239, 222, 205)", "name": "Almond"}
    {"hex": "#CD9575", "rgb": "(205, 149, 117)", "name": "Antique Brass"}
    {"hex": "#FDD9B5", "rgb": "(253, 217, 181)", "name": "Apricot"}
    {"hex": "#78DBE2", "rgb": "(120, 219, 226)", "name": "Aquamarine"}
    {"hex": "#87A96B", "rgb": "(135, 169, 107)", "name": "Asparagus"}
    

    我们可以使用 to_json() 函数将 color_jsonb 列转换回 json 格式,但它没有 返回原始键顺序。

    ugautil=> select to_json(color_jsonb) from crayons limit 5;
    ----------------------------------------------------------------
    {"hex": "#EFDECD", "rgb": "(239, 222, 205)", "name": "Almond"}
    {"hex": "#CD9575", "rgb": "(205, 149, 117)", "name": "Antique Brass"}
    {"hex": "#FDD9B5", "rgb": "(253, 217, 181)", "name": "Apricot"}
    {"hex": "#78DBE2", "rgb": "(120, 219, 226)", "name": "Aquamarine"}
    {"hex": "#87A96B", "rgb": "(135, 169, 107)", "name": "Asparagus"}
    

    但是我们可以挑选出单独的键并对其进行格式化。

    ugautil=>   select format('{"hex": %s,"name": %s, "rgb": %s}', 
    color_jsonb->'hex',color_jsonb->'name', color_jsonb->'rgb') 
    from crayons limit 5;
    ----------------------------------------------------------------
    {"hex": "#EFDECD","name": "Almond", "rgb": "(239, 222, 205)"}
    {"hex": "#CD9575","name": "Antique Brass", "rgb": "(205, 149, 117)"}
    {"hex": "#FDD9B5","name": "Apricot", "rgb": "(253, 217, 181)"}
    {"hex": "#78DBE2","name": "Aquamarine", "rgb": "(120, 219, 226)"}
    {"hex": "#87A96B","name": "Asparagus", "rgb": "(135, 169, 107)"}
    

    更改表以创建一个新列来保存您想要的 json 类型

    ugautil=> alter table crayons add column color_json2 json;
    

    使用从 jsonb 中选择的查询更新表 列,并按您想要的顺序格式化键,并使用它 更新新的 color_json2 列。

    with subquery as (
    select id,
    format('{"hex": %s,"name": %s, "rgb": %s}', 
    color_jsonb->'hex',color_jsonb->'name', 
    color_jsonb->'rgb') as "color_json2_fmt"
    from crayons
    )
    update crayons
    set color_json2 = subquery.color_json2_fmt::json
    from subquery
    where crayons.id = subquery.id;
    
    
    ugautil=> select color_json2 from crayons limit 5;
    color_json2                              
    ---------------------------------------------------------------
    {"hex": "#EFDECD","name": "Almond", "rgb": "(239, 222, 205)"}
    {"hex": "#CD9575","name": "Antique Brass", "rgb": "(205, 149, 117)"}
    {"hex": "#FDD9B5","name": "Apricot", "rgb": "(253, 217, 181)"}
    {"hex": "#78DBE2","name": "Aquamarine", "rgb": "(120, 219, 226)"}
    {"hex": "#87A96B","name": "Asparagus", "rgb": "(135, 169, 107)"}
    

    Explanation of JSONB introduced by PostgreSQL
    updating table rows in postgres using subquery

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-09
      • 1970-01-01
      • 2021-04-16
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多