【问题标题】:postgresql - Aggregate function calls cannot be nested. How can I format this query in a nice json format?postgresql - 不能嵌套聚合函数调用。如何以漂亮的 json 格式格式化此查询?
【发布时间】:2021-10-25 12:40:18
【问题描述】:

我正在尝试创建一个以漂亮的 json 格式返回数据的 psql 查询。最初对于我们使用 sequelize 的项目,我正在尝试将其转换为纯 psql。我要找的格式如下-

...
vehicles:
[
  {
    services: 
    [
      {
        name: "example"
        duration: "example"
      }
    ]
    id: 1
    registration: "example"
  }
]
...

以下是我首先尝试但得到错误的方法。 错误:聚合函数调用不能嵌套

SELECT
   "Bookings"."id",
   "Bookings"."startTime",
   "Bookings"."code",
   "Bookings"."statusId",
   "Bookings"."address",
   "Bookings"."latitude",
   "Bookings"."longitude",
   "Bookings"."createdAt",
   "Bookings"."overridePrice",
   
   json_build_object(
       'fullName', "customer"."fullName",
       'id', "customer"."id"
   ) AS "customer",
   
   json_agg(json_build_object(
       'fullName', "serviceProvider"."fullName", 
       'id', "serviceProvider"."id"
   )) AS "serviceProvider",
   
-- Array of vehicles, this is where the issue lies
   json_agg(
       json_build_object(
       'services', json_agg(
           json_build_object(
                'name', "ServiceHistories"."name",
                'duration', "ServiceHistories"."duration"
            )
       ),
       'id', "Vehicles"."id", 
       'registration', "Vehicles"."registration"
   )) AS "vehicles",
--  Everything else works fine
   
   json_agg(
       json_build_object(
           'amount', "payments"."amount",
           'amountFromGiftCard', "payments"."amountFromGiftCard"
       )
   ) AS "payments"
   
FROM
   "Bookings",
   "Users" AS "customer",
   "Users" AS "serviceProvider",
   "BookingServiceProviders",
   "BookingVehicleServices",
   "BookingVehicles",
   "Vehicles",
   "Payments" AS "payments",
   "ServiceHistories"
WHERE
    "Bookings"."isDeleted" IS NOT true AND
    "Bookings"."statusId" != 4 AND
    "Bookings"."customerId" = "customer"."id" AND "customer"."userTypeId" = 1 AND
    "Bookings"."id" = "BookingServiceProviders"."BookingId" AND
    "BookingServiceProviders"."UserId" = "serviceProvider"."id" AND
    "Bookings"."id" = "BookingVehicles"."BookingId" AND
    "Vehicles"."id" = "BookingVehicles"."VehicleId" AND
    "Bookings"."id" = "payments"."bookingId" AND
    "BookingVehicles"."id" = "BookingVehicleServices"."BookingVehicleId" AND
    "ServiceHistories"."bookingId" = "Bookings"."id"
GROUP BY 
    "Bookings"."id",
    "customer"."id",
    "customer"."fullName"
Order by "startTime" ASC

做了一些谷歌搜索后,我发现我可能需要对服务数组进行子查询。以下是我尝试过的,但查询会无限期运行。

SELECT
   "Bookings"."id",
   "Bookings"."startTime",
   "Bookings"."code",
   "Bookings"."statusId",
   "Bookings"."address",
   "Bookings"."latitude",
   "Bookings"."longitude",
   "Bookings"."createdAt",
   "Bookings"."overridePrice",
   
   json_build_object(
       'fullName', "customer"."fullName",
       'id', "customer"."id"
   ) AS "customer",
   
   json_agg(json_build_object(
       'fullName', "serviceProvider"."fullName", 
       'id', "serviceProvider"."id"
   )) AS "serviceProvider",
   
   -- Issue lies here
   json_agg(
       json_build_object(
           'services', (
               SELECT 
                    json_agg(json_build_object(
                        'name', "ServiceHistories"."name",
                       'duration', "ServiceHistories"."duration"
                    ))
               FROM
                    "ServiceHistories"
               WHERE
                    "ServiceHistories"."bookingId" = "Bookings"."id"
           ),
       'id', "Vehicles"."id", 
       'registration', "Vehicles"."registration"
   )) AS "vehicles",
   -- End of issue
   
   json_agg(
       json_build_object(
           'amount', "payments"."amount",
           'amountFromGiftCard', "payments"."amountFromGiftCard"
       )
   ) AS "payments"
   
FROM
   "Bookings",
   "Users" AS "customer",
   "Users" AS "serviceProvider",
   "BookingServiceProviders",
   "BookingVehicleServices",
   "BookingVehicles",
   "Vehicles",
   "Payments" AS "payments"
WHERE
    "Bookings"."isDeleted" IS NOT true AND
    "Bookings"."statusId" != 4 AND
    "Bookings"."customerId" = "customer"."id" AND "customer"."userTypeId" = 1 AND
    "Bookings"."id" = "BookingServiceProviders"."BookingId" AND
    "BookingServiceProviders"."UserId" = "serviceProvider"."id" AND
    "Bookings"."id" = "BookingVehicles"."BookingId" AND
    "Vehicles"."id" = "BookingVehicles"."VehicleId" AND
    "Bookings"."id" = "payments"."bookingId" AND
    "BookingVehicles"."id" = "BookingVehicleServices"."BookingVehicleId"
GROUP BY 
    "Bookings"."id",
    "customer"."id",
    "customer"."fullName"
Order by "startTime" ASC

如果有人可以帮助或指出正确的方向,我将不胜感激。

** 编辑 **

我通过添加更多关于表如何关联的 where 子句来使其工作,现在服务在车辆数组中正确返回。可悲的是它的超级慢。我让它工作得更快,但是当它应该只是与特定预订相关的服务时,却出现了重复的服务。

SELECT
   bookings."id",
   bookings."startTime",
   bookings."code",
   bookings."statusId",
   bookings."address",
   bookings."latitude",
   bookings."longitude",
   bookings."createdAt",
   bookings."overridePrice",
   
   json_build_object(
       'fullName', "customer"."fullName",
       'id', "customer"."id"
   ) AS "customer",
   
   json_agg(json_build_object(
       'fullName', "serviceProvider"."fullName", 
       'id', "serviceProvider"."id"
   )) AS "serviceProvider",
   
   json_agg(
       json_build_object(
           'amount', "payments"."amount",
           'amountFromGiftCard', "payments"."amountFromGiftCard"
       )
   ) AS "payments",
   
    (
        SELECT 
        (nested_vehicles)
        FROM (
            SELECT
                "Vehicles".id as vehicle_id,
                "Vehicles".registration,
                (
                    SELECT 
                        json_agg(nested_services)
                    FROM (
                        SELECT
                            "ServiceHistories"."id",
                            "ServiceHistories"."name",
                            "ServiceHistories"."duration"
                        FROM 
                            "ServiceHistories", "BookingVehicleServices", "BookingVehicles"
                        WHERE 
                            "ServiceHistories"."vehicleId" = "Vehicles"."id" AND 
                            "ServiceHistories"."id" = "BookingVehicleServices"."ServiceHistoryId" AND
                            bookings.id = "BookingVehicles"."BookingId" AND
                            "Vehicles"."id" = "BookingVehicles"."VehicleId" AND
                            "ServiceHistories"."bookingId" = bookings.id 
                            
                    ) AS nested_services
                ) AS services
            FROM 
                "Vehicles", "BookingVehicles"
            WHERE "Vehicles"."id" = "BookingVehicles"."VehicleId" AND bookings.id = "BookingVehicles"."BookingId"
            GROUP BY "Vehicles"."id"
        ) AS nested_vehicles
    ) AS vehicles
FROM 
    "Bookings" as bookings,
    "Users" AS "customer",
    "Users" AS "serviceProvider",
    "BookingServiceProviders",
    "Payments" AS "payments"
WHERE
    bookings."isDeleted" IS NOT true AND
    bookings."statusId" != 4 AND
    bookings."customerId" = "customer"."id" AND "customer"."userTypeId" = 1 AND
    bookings."id" = "BookingServiceProviders"."BookingId" AND
    "BookingServiceProviders"."UserId" = "serviceProvider"."id" AND
    bookings."id" = "payments"."bookingId"
GROUP BY 
    bookings."id",
    "customer"."id",
    "customer"."fullName"
Order by "startTime" ASC

不太确定在这里做什么。我可能只是单独返回服务,然后在外部格式化它们:/

【问题讨论】:

    标签: sql json postgresql aggregate


    【解决方案1】:

    错误:聚合函数调用不能嵌套

    不确定最佳实践,但我使用 subqueriesCommon Table Expressions (CTE)

    第一个聚合函数调用来自子查询/CTE,第二个聚合函数调用来自查询。

    -- Common Table Expressions
    WITH regional_sales AS (
            SELECT region, SUM(amount) AS total_sales
            FROM orders
            GROUP BY region
         ), top_regions AS (
            SELECT region
            FROM regional_sales
            WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
         )
    SELECT region,
           product,
           SUM(quantity) AS product_units,
           SUM(amount) AS product_sales
    FROM orders
    WHERE region IN (SELECT region FROM top_regions)
    GROUP BY region, product;
    

    【讨论】:

    • 嗯,我试过使用子查询,这是问题中的第二个代码块。它只是无限期地运行,从不返回结果。一定是有什么问题,但无法发现
    • 将查询“车辆数组”拆分为子查询。
    • 查看我上面的编辑,将它们分成更多的子查询。可悲的是它超级慢,我的查询需要很长时间才能运行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 2019-06-07
    相关资源
    最近更新 更多