在数组列上使用内部联接时重复的值

时间:2017-05-03 22:43:29

标签: sql postgresql

我有一个appointment表,其中两个字段petsservices是数组。除了与该约会相关的服务和宠物的名称之外,我还尝试制作一个列出starts_atends_at时间的查询。

我遇到的问题是,如果petsservices包含的值超过1,我会在输出中遇到重复的值。

这是我目前的查询:

SELECT
    appointment.starts_at,
    appointment.ends_at,
    string_agg(service.name, ', ') AS service_names,
    string_agg(pet.name, ', ') AS pet_names
FROM get_appointments(20, CURRENT_DATE, CAST((CURRENT_DATE + INTERVAL '1 day' * 4) AS DATE), null, null) AS appointment
INNER JOIN pet on pet.id = ANY(appointment.pets)
INNER JOIN service on service.id = ANY(appointment.services)
GROUP BY
    appointment.starts_at,
    appointment.ends_at
ORDER BY
    appointment.starts_at ASC;

此处的示例输出:

+---------------------+---------------------+--------------------------------+-------------------+
|      starts_at      |       ends_at       |         service_names          |     pet_names     |
+---------------------+---------------------+--------------------------------+-------------------+
| 2017-05-03 07:00:00 | 2017-05-03 07:30:00 | 30 Minute Walk, 30 Minute Walk | Gregor, The Hound |
+---------------------+---------------------+--------------------------------+-------------------+

这是所需的输出:

+---------------------+---------------------+--------------------------------+-------------------+
|      starts_at      |       ends_at       |         service_names          |     pet_names     |
+---------------------+---------------------+--------------------------------+-------------------+
| 2017-05-03 07:00:00 | 2017-05-03 07:30:00 | 30 Minute Walk          | Gregor, The Hound |
+---------------------+---------------------+--------------------------------+-------------------+

我正在运行Postgres 9.5。

谢谢!

1 个答案:

答案 0 :(得分:1)

SELECT
    appointment.starts_at,
    appointment.ends_at,
    (select string_agg(service.name, ', ') from service where service.id = ANY(appointment.services)) AS service_names,
    (select string_agg(pet.name, ', ') from pet where pet.id = ANY(appointment.pets)) AS pet_names
FROM get_appointments(20, CURRENT_DATE, CAST((CURRENT_DATE + INTERVAL '1 day' * 4) AS DATE), null, null) AS appointment
GROUP BY
    appointment.starts_at,
    appointment.ends_at
ORDER BY
    appointment.starts_at ASC;

同样使用lateral joins

SELECT
    appointment.starts_at,
    appointment.ends_at,
    service_names,
    pet_names
FROM get_appointments(20, CURRENT_DATE, CAST((CURRENT_DATE + INTERVAL '1 day' * 4) AS DATE), null, null) AS appointment
  cross join lateral (
    select string_agg(service.name, ', ')  AS service_names
    from service
    where service.id = ANY(appointment.services)) as srv
  cross join lateral (
    select string_agg(pet.name, ', ')  AS pet_names
    from pet
    where pet.id = ANY(appointment.pets)) as pet
GROUP BY
    appointment.starts_at,
    appointment.ends_at
ORDER BY
    appointment.starts_at ASC;