PostgreSQL: пропустить выбор строки, если найдено более одной строки с одинаковым значением столбца

У меня есть следующий выбор:

SELECT
    posm.id AS org_scope_metric_id,
    cc.code AS control_code,
    ccp.code AS part_code,
    pop.id AS program_id
FROM public.org_scope_metric posm
JOIN public.org_metric pom ON pom.id = posm.metric_id
JOIN compliance.metric cm ON cm.id = pom.metric_id
JOIN compliance.control_part_metric ccpm ON ccpm.metric_id = cm.id
JOIN compliance.control_part ccp ON ccp.id = ccpm.part_id
JOIN compliance.control cc ON cc.id = ccp.control_id
JOIN compliance.program_framework cpf ON cpf.framework_id = cc.framework_id
JOIN public.org_program pop ON pop.program_id = cpf.program_id
WHERE posm.scope_id ='e6d11bfe-e5fc-11ee-8cda-238cdb93d281'
GROUP BY posm.id, cc.code, ccp.code, pop.id

который возвращает такой результат:

Если есть org_scope_metric_ids с разными program_id, мне нужно пропустить их все из выбора.

Пожалуйста, помогите решить проблему!

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
3
57
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Подсчитайте количество одинаковых вхождений org_scope_metric_id и количество различных program_id-ов в каждой группе, а затем отфильтруйте строки результатов, в которых оба числа больше 1.

with t as ( 
  select *, 
    count(*) over w cnt,
    array_agg(program_id) over w program_id_list
  from (<your query here>) t 
  window w as (partition by org_scope_metric_id)
)
select * from t 
where cnt > 1 and array_distinct_count(program_id_list) > 1;

Для этого вам понадобится вспомогательная функция -

create or replace function array_distinct_count(arr anyarray)
returns integer language sql immutable as $$
 select count(distinct el) from unnest(arr) el;
$$;

Я получаю ошибку DISTINCT is not implemented for window functions :(

Vyacheslav Fedorin 23.03.2024 11:59

Ой, пропустил это. Ответ обновлен.

Stefanov.sm 23.03.2024 13:14

Вы можете использовать оконные функции min и max.

SELECT *
FROM (
    SELECT
        posm.id AS org_scope_metric_id,
        cc.code AS control_code,
        ccp.code AS part_code,
        pop.id AS program_id,
        MIN(pop.id) OVER (PARTITION BY posm.id) = MAX(pop.id) OVER (PARTITION BY posm.id) AS all_same_id
    FROM public.org_scope_metric posm
    JOIN public.org_metric pom ON pom.id = posm.metric_id
    JOIN compliance.metric cm ON cm.id = pom.metric_id
    JOIN compliance.control_part_metric ccpm ON ccpm.metric_id = cm.id
    JOIN compliance.control_part ccp ON ccp.id = ccpm.part_id
    JOIN compliance.control cc ON cc.id = ccp.control_id
    JOIN compliance.program_framework cpf ON cpf.framework_id = cc.framework_id
    JOIN public.org_program pop ON pop.program_id = cpf.program_id
    WHERE posm.scope_id ='e6d11bfe-e5fc-11ee-8cda-238cdb93d281'
    GROUP BY posm.id, cc.code, ccp.code, pop.id
) p
WHERE all_same_id;

Почему бы не переместить MIN(pop.id) OVER (PARTITION BY posm.id) = MAX(pop.id) OVER (PARTITION BY posm.id) в предложение WHERE? и устранение необходимости в подзапросе?

Luuk 24.03.2024 15:17

Потому что вы не можете поместить оконные функции в WHERE, только в предложение QUALIFY, которое Postgres не поддерживает.

Charlieface 24.03.2024 15:18

Большое вам спасибо, ребята. Мое окончательное решение в соответствии с вашими предложениями:

SELECT
   org_scope_metric_id,
   program_scope_id,
   array_agg(program_scope_id) OVER (PARTITION BY org_scope_metric_id) AS metric_program_scopes
FROM (
  <long_selection_from_the_question>
) subquery
GROUP BY subquery.org_scope_metric_id, subquery.program_scope_id

Итак, главное, что мне пришлось использовать OVER (PARTITION BY), чтобы получить необходимое количество.

Другие вопросы по теме