Postgres:什么可能导致错误“无法在标量上调用 populate_composite”?

Bra*_*don 5 postgresql postgresql-10

我有一列 type JSONB,其中每一行都包含一个带有对象数组的 JSON,例如:

[
    {
        "grade": "4.44/5",
        "endYear": 2011,
        "startYear": 2006,
        "userId": "defg"
    },
    {
        "grade": "9.133/10",
        "endYear": 2010,
        "startYear": 2006,
        "userId": "abcd"
    }
]
Run Code Online (Sandbox Code Playgroud)

我正在尝试将这些JSONB集合扩展为行,例如:

| grade    | startYear | endYear | userId |
-------------------------------------------
| 4.44/5   |    2006   | 2011    | defg   |
| 9.133/10 |    2006   | 2010    | abcd   |
-------------------------------------------
Run Code Online (Sandbox Code Playgroud)

..使用以下查询:

WITH arr AS (SELECT jsonb_array_elements(jsonbrecords) AS jsons
             FROM "table-with-jsonb"),
    lines AS (
      SELECT x.*
      FROM arr, jsonb_to_record(jsons) AS x(
                "field1" VARCHAR
                 )
  ) SELECT *
    FROM lines
Run Code Online (Sandbox Code Playgroud)

我正在使用 Datagrip,它对结果进行分页,并且查询对前 500 行完成得很好。

但是,当我尝试加载最后一页结果时,出现此错误:

[22023] ERROR: cannot call populate_composite on a scalar

除了Postgres 源代码之外,谷歌搜索这个错误几乎没有任何有用的结果(对我来说是第一次)。

我不会说 C,但由于jsonb_array_elementsCTE 本身评估得很好,我假设问题是某些行在列中具有标量值jsonbrecords而不是正确的JSONB.

为了确保我只有JSONB值,我删除了不包含'{'在此查询中的行:

UPDATE  "table-with-jsonb" SET jsonbrecords = NULL
WHERE jsonbrecords :: TEXT !~ '{'
Run Code Online (Sandbox Code Playgroud)

这删除了大约十二行,但错误仍然存​​在。

我还尝试通过检查JSONB表中的原始行来查找问题,但什么也没找到。

我认为错误意味着一行中没有JSONB值是否正确?如果是这样,我该如何解决?如果没有,我该如何调试?

a_h*_*ame 7

无关,但是:您可以将查询简化为:

SELECT x.*
from the_table, 
     jsonb_array_elements(jsonbrecords) AS t(doc),
     jsonb_to_record(t.doc) as x ("grade" text, "userId" text, "endYear" int, "startYear" int);
Run Code Online (Sandbox Code Playgroud)

现在是实际问题。可以通过不jsonb_to_record单独使用和访问每个键来避免该错误:

SELECT t.doc ->> 'grade' as "grade",
       t.doc ->> 'endYear' as "endYear", 
       t.doc ->> 'startYear' as "startYear",
       t.doc ->> 'userId' as "userId"
from the_table, 
     jsonb_array_elements(jsonbrecords) AS t(doc);
Run Code Online (Sandbox Code Playgroud)

您并没有真正失去灵活性,因为您还需要指定列列表jsonb_to_record()

在线示例:http : //rextester.com/VVGJ34083