5

注意:我使用的是最新版本的 Postgres (9.4)

我正在尝试编写一个查询,它对 2 个表进行简单的连接,并按第一个表的主键进行分组,并对第二个表中的几个字段进行 array_agg,我希望将其作为对象返回。该数组需要通过 json 对象中的 2 个字段的组合进行排序,并且也是唯一的。

到目前为止,我想出了以下几点:

SELECT  
  zoo.id,  
  ARRAY_AGG(
    DISTINCT ROW_TO_JSON(( 
      SELECT x  
      FROM ( 
        SELECT animals.type, animals.name 
      ) x
    ))::JSONB
    -- ORDER BY animals.type, animals.name
  )
  FROM zoo
  JOIN animals ON animals.zooId = zoo.id
  GROUP BY zoo.id;

这导致每个动物园有一行,有一个 jsonb 对象的聚合数组,每个动物一个,唯一。

但是,我似乎无法弄清楚如何通过代码注释部分中的参数对其进行排序。

如果我取出不同的,我可以按原始字段排序,效果很好,但是我有重复项。

4

1 回答 1

2

如果您使用row_to_json(),除非您输入已键入的行,否则您将丢失列名。如果您使用显式名称“手动”构建jsonb对象,json_build_object()那么您可以将它们取回:

SELECT zoo.id, array_agg(za.jb) AS animals
FROM zoo
JOIN (
  SELECT DISTINCT ON (zooId, "type", "name")
    zooId, json_build_object('animal_type', "type", 'animal_name', "name")::jsonb AS jb
  FROM animals
  ORDER BY zooId, jb->>'animal_type', jb->>'animal_name'
  -- ORDER BY zooId, "type", "name" is far more efficient
) AS za ON za.zooId = zoo.id
GROUP BY zoo.id;

您可以ORDER BY使用对象的元素jsonb,如上所示,但是(据我所知)您不能DISTINCTjsonb对象上使用。在您的情况下,无论如何这将是相当低效的(首先构建所有jsonb对象,然后丢弃重复项),并且在聚合级别使用标准 SQL 显然是不可能的。但是,您可以通过在构建对象DISTINCT之前应用该子句来获得相同的结果。jsonb

此外,避免使用SQL 关键字(如“type”)和标准数据类型(如“name”)作为列名。两者都是非保留关键字,因此您可以在适当的上下文中使用它们,但实际上您的命令可能会变得非常混乱。例如,你可以有一个模式,一个表,该表中的一个列,以及一个数据类型,每个数据类型都称为“类型”,然后你可以得到这个:

SELECT type::type FROM type.type WHERE type = something;

虽然 PostgreSQL 会欣然接受这一点,但它充其量只是令人困惑,并且在各种更复杂的情况下容易出错。你可以通过双引号来获得很长的路要走任何关键词,但最好避免将它们作为标识符。

于 2015-05-16T07:41:42.560 回答