【问题标题】:How to create an empty JSON object in postgresql?如何在 postgresql 中创建一个空的 JSON 对象?
【发布时间】:2016-01-23 03:30:21
【问题描述】:

数据模型

一个人在数据库中表示为具有名称和多个属性的元表行,这些属性以键值对的形式存储在数据表中(键和值位于不同的列中)。 简化的数据模型

现在有一个查询来检索所有用户(name)及其所有属性(data)。属性在单独的列中作为 JSON 对象返回。这是一个例子:

name      data
Florian   { "age":25 }
Markus    { "age":25, "color":"blue" }
Thomas    {}

SQL 命令如下所示:

SELECT
  name,
  json_object_agg(d.key, d.value) AS data,
FROM meta AS m
JOIN (
  JOIN d.fk_id, d.key, d.value AS value FROM data AS d
  ) AS d
ON d.fk_id = m.id
GROUP BY m.name;

问题

现在我面临的问题是,像 Thomas 这样没有任何属性存储在 key-value 表中的用户没有显示在我的选择函数中.这是因为它只执行JOIN 而没有LEFT OUTER JOIN

如果我使用LEFT OUTER JOIN,那么我会遇到问题,即json_object_agg 尝试聚合NULL 值并因错误而死。

方法

1。返回键和值的空列表

所以我尝试检查用户的 key-column 是否为 NULL 并返回一个空数组,因此 json_object_agg 只会创建一个空的 JSON 对象.

但是在 SQL 中实际上并没有创建空数组的函数。我找到的最接近的东西是这样的:

select '{}'::text[];

结合COALESCE,查询看起来像这样:

json_object_agg(COALESCE(d.key, '{}'::text[]), COALESCE(d.value, '{}'::text[])) AS data

但如果我尝试使用它,我会收到以下错误:

ERROR:  COALESCE types text and text[] cannot be matched
LINE 10:     json_object_agg(COALESCE(d.key, '{}'::text[]), COALES...
                                                ^
Query failed
PostgreSQL said: COALESCE types text and text[] cannot be matched

所以在运行时d.key 看起来是单个值而不是数组。

2。拆分 JSON 创建并返回空列表

所以我尝试将json_object_agg 替换为json_object,它不会为我聚合密钥:

json_object(COALESCE(array_agg(d.key), '{}'::text[]), COALESCE(array_agg(d.value), '{}'::text[])) AS data

但是我得到了null value not allowed for object key 的错误。所以COALESCE 不会检查数组是否为空。

问题

那么,是否有一个函数可以检查连接的列是否为空,如果是,则只返回一个简单的 JSON 对象?

或者有没有其他解决方案可以解决我的问题?

【问题讨论】:

  • “看起来在运行时 d.key 是单个值而不是数组” - 我不确定“在运行时”是什么意思。如果d.key 是一个列,那么你必须知道它是什么类型。从错误消息来看,它似乎是类型text;所以空值是''(或者text ''''::text,如果你想明确的话)。
  • 是的,它只是文本。但我认为这将是一个文本列表,因为我在那里引用了整个专栏。但那是我对 SQL 语法的误解。所以 在运行时 我的意思是查询何时执行。
  • 啊,是的,我明白了。作为一个更清楚的例子,它引用的是一个值而不是整个列,请考虑以下工作:Select sum(some_column + 1) From some_table - +1 必须在将它们捆绑到 sum 之前分别对每个值进行操作。

标签: json postgresql postgresql-9.4


【解决方案1】:

left joincoalesce() 一起使用。作为默认值使用'{}'::json

select name, coalesce(d.data, '{}'::json) as data
from meta m
left join (
    select fk_id, json_object_agg(d.key, d.value) as data
    from data d
    group by 1
    ) d
on m.id = d.fk_id;

  name   |                data                
---------+------------------------------------
 Florian | { "age" : "25" }
 Marcus  | { "age" : "25", "color" : "blue" }
 Thomas  | {}
(3 rows)    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-01
    • 2013-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多