【问题标题】:PostgreSQL: Aggregate multiple rows as JSON array based on specific columnPostgreSQL:基于特定列将多行聚合为 JSON 数组
【发布时间】:2018-10-31 15:22:14
【问题描述】:

我有一个表 data_tracks 包含点(纬度经度),记录在特定时间(created_at) 并且属于旅行 (trip_log_id)。一次旅行通常至少有两个点(起点和终点)。

表:data_tracks

  • created_at : text
  • latitude : float
  • longitude : float
  • trip_log_id : integer

我想生成一个 JSON 输出,由数组组成,而每个内部数组都包含行程的聚合点(如 trip_log_id 所示)。

由两次旅行组成的示例:

[

  [
    {
      "latitude": 52.504873,
      "longitude": 13.396681,
      "recorded_at": "2018-10-11T15:16:32.775"
    },
    {
      "latitude": 52.505225,
      "longitude": 13.396976,
      "recorded_at": "2018-10-11T15:16:32.807"
    },
    {
      "latitude": 52.505372,
      "longitude": 13.397035,
      "recorded_at": "2018-10-11T15:16:32.835"
    },
  ],

  [
    {
      "latitude": 52.5242370846803,
      "longitude": 13.3443558528637,
      "recorded_at": "2018-10-11T11:22:54.666"
    },
    {
      "latitude": 52.5242366166393,
      "longitude": 13.3443558656828,
      "recorded_at": "2018-10-11T11:22:54.727"
    }
  ]

]

根据另一篇帖子[1] 的建议,我能够生成一个非常接近我正在寻找的输出。但是,输出被解释为文本,其中引入了不需要的转义字符。此外,缺少外部数组。

查询应该在 PostgreSQL 9.3 上运行。

自适应查询:

SELECT Array_agg(rw) 
FROM  (SELECT trip_log_id, 
              (SELECT To_json(Array_agg(Row_to_json(t))) 
               FROM   (SELECT latitude, 
                              longitude, 
                              created_at AS recorded_at 
                       FROM   public.data_tracks 
                       WHERE  trip_log_id = b.trip_log_id) t) rw 
       FROM   data_tracks b 
       GROUP  BY trip_log_id) z; 

输出:

{

    "[
        {
            \"latitude\":52.504873,
            \"longitude\":13.396681,
            \"recorded_at\":\"2018-10-11T15:16:32.775\"
        },
        {
            \"latitude\":52.505225,
            \"longitude\":13.396976,
            \"recorded_at\":\"2018-10-11T15:16:32.807\"
        },
        {
            \"latitude\":52.505372,
            \"longitude\":13.397035,
            \"recorded_at\":\"2018-10-11T15:16:32.835\"
        },
        {
            \"latitude\":52.505686,
            \"longitude\":13.397218,
            \"recorded_at\":\"2018-10-11T15:16:32.871\"
        },
        {
            \"latitude\":52.505921,
            \"longitude\":13.397389,
            \"recorded_at\":\"2018-10-11T15:16:32.906\"
        },
        {
            \"latitude\":52.506166,
            \"longitude\":13.397593,
            \"recorded_at\":\"2018-10-11T15:16:32.936\"
        },
        {
            \"latitude\":52.50647,
            \"longitude\":13.397856,
            \"recorded_at\":\"2018-10-11T15:16:32.969\"
        },
        {
            \"latitude\":52.506786,
            \"longitude\":13.398065,
            \"recorded_at\":\"2018-10-11T15:16:33\"
        }
    ]",

    "[
        {
            \"latitude\":52.5242370846803,
            \"longitude\":13.3443558528637,
            \"recorded_at\":\"2018-10-11T11:22:54.666\"
        },
        {
            \"latitude\":52.5242366166393,
            \"longitude\":13.3443558656828,
            \"recorded_at\":\"2018-10-11T11:22:54.727\"
        }
    ]"

}

【问题讨论】:

    标签: sql json postgresql postgresql-9.3


    【解决方案1】:

    免责声明:仅适用于 Postgres 9.4+ 9.4 及更高版本为 Postgres 添加了对 JSON 的巨大支持。 9.3 已经不受支持。你真的应该升级你的数据库。

    demo:db<>fiddle

    SELECT json_agg(trips)
    FROM (
        SELECT 
            json_agg(
                json_build_object(
                    'recorded_at', created_at, 
                    'latitude', latitude, 
                    'longitude', longitude
                )
            ) as trips
        FROM data_tracks
        GROUP by trip_log_id
    )s
    
    1. json_build_object 创建您的主要 json 对象
    2. json_agg() ... GROUP BY trip_log_id 将这些 json 对象组合成一个行程对象
    3. second json_agg 将所有行程聚合到一个数组中

    demo:SQL Fiddle

    9.3 版本(绝对不推荐!)

    SELECT json_agg(trips)
    FROM (
        SELECT 
            json_agg(
                ('{"recorded_at":"' || created_at || 
                '","latitude":' || latitude || 
                ',"longitude":' || longitude || '}')::json
            ) as trips
        FROM data_tracks
        GROUP by trip_log_id
    )s
    

    【讨论】:

    • 谢谢,你拯救了我的一天!很抱歉没有提供小提琴,会节省你的时间。我可以在本地开发环境(Postgres 9.5)上成功测试它;我也会按照您的建议将生产环境升级到 9.5。
    • 已经为 9.3 添加了一个版本。不过,您为什么要更新到另一个旧版本。我建议至少 9.6(现在稳定是 11!)
    • 我只是想进行最小的必要更改会更安全,因为我们使用的是jruby-pg,并且没有明确声明与 Postgres 11 兼容。他们用于测试的版本是 9.3.6。
    • 我不知道你的工具。但恕我直言,切换到 9.6 绝对安全。 IIRC 在版本 10 中更改了一些专门的细节,因此应该更加努力地进行测试。但在正常情况下,没有理由在 PostgreSQL 世界中老去。更改在其更改日志中准确描述。如果您不确定,请仔细阅读。
    • 感谢您分解层次结构步骤。你拯救了我的一天!
    猜你喜欢
    • 2021-09-24
    • 1970-01-01
    • 2018-01-14
    • 2017-09-28
    • 2022-08-16
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    相关资源
    最近更新 更多