Запрос Postgresql для возврата отфильтрованного результата

#sql #postgresql

#sql #postgresql

Вопрос:

Мой запрос

     select link.id, bti_status.bti_status from link
inner join bti
    on link.id = bti.id
inner join bti_status
    on bti.id = bti_status.bti_id
  

возвращает следующую таблицу.

введите описание изображения здесь

Я хотел бы, чтобы этот запрос возвращал только набор идентификаторов, у которых нет bti_status = 4, поэтому ни в одной из строк не должно быть возвращено id = 403, поскольку строка 5 имеет значение bti_status, равное 4.

Я пробовал следующий запрос, но я не уверен, правильно ли он выполняет работу.

     select link.id, bti_status.bti_status from link
inner join bti
    on link.id = bti.id
inner join bti_status
    on bti.id = bti_status.bti_id
where not exists (select bti_status from bti_status where bti_status = 4);
  

Обновить

Что касается ответа @GMB, мой исходный запрос на самом деле отличается от того, который я опубликовал. Исходный запрос

 select link.id, bti_status.bti_status, bti.id from link
inner join bti_link
    on link.id = bti_link.id
inner join bti
    on bti_link.bti_id = bti.id
inner join deadline
    on deadline.id = link.deadline_id
inner join bti_status
    on bti.id = bti_status.bti_id
where deadline.id = :id
and not exists (select bti_status from bti_status where bti_status = 4);
  

и если я попробую ваше решение, я не смогу заставить его работать

 select l.id, bs.bti_status, b.id 
from (
        select l.id, bs.bti_status, b.id, 
            bool_or(bs.bti_status = 4) over(partition by l.id) has_status_4
        from link l
        inner join bti_link on l.id = bti_link.id
        inner join bti b on bti_link.bti_id = b.id
        inner join deadline d on d.id = l.deadline_id
        inner join bti_status bs on b.id = bs.bti_id
) t
where d.id = :id
and not has_status_4;
  

Ответ №1:

как сказал GMB, функция window — это один из способов.

вы также можете использовать CTE:

 WITH data AS (
   SELECT link.id AS link_id, bti_status.bti_status, bti.id AS bti_id
   FROM link
   INNER JOIN bti_link ON link.id = bti_link.id
   INNER JOIN bti ON bti_link.bti_id = bti.id
   INNER JOIN deadline ON deadline.id = link.deadline_id
   INNER JOIN bti_status ON bti.id = bti_status.bti_id
   WHERE deadline.id = :id
   )
SELECT * 
FROM data
WHERE link_id NOT IN (
   SELECT link_id 
   FROM data 
   WHERE bti_status = 4)
  

Комментарии:

1. Я не могу заставить его работать. я получаю сообщение об ошибке «Ошибка SQL [42702]: ОШИБКА: ссылка на столбец «id» неоднозначна Позиция: 376 ОШИБКА: ссылка на столбец «id» неоднозначна Позиция: 376 ОШИБКА: ссылка на столбец «id» неоднозначна Позиция: 376 »

2. Я отредактировал имена столбцов. попробуйте сейчас. в исходном запросе было два столбца с именем id .

Ответ №2:

Вы можете сделать это с помощью оконных функций. Вот один из способов сделать это с помощью логической агрегации окон:

 select id, bti_status
from (
    select l.id, bs.bti_status, 
        bool_or(bs.bti_status = 4) over(partition by l.id) has_status_4
    from link l
    inner join bti b on l.id = b.id
    inner join bti_status bs on b.id = bs.bti_id
) t
where not has_status_4
  

Комментарии:

1. @Marko: удалите префиксы l , bs и d во внешнем select предложении (или используйте t везде): они не определены в этой области. Итак: select id, bti_status from (...) t where id = :id and not has_status_4 . Кроме того, у вас есть два столбца, вызываемых id в подзапросе, это неоднозначно. Вам нужно указать псевдоним хотя бы одного из них.

2. Когда я это делаю, я получаю «Ошибка SQL [42P01]: ОШИБКА: отсутствует запись в предложении для таблицы «link» Позиция: 8 ОШИБКА: отсутствует запись в предложении для таблицы «link» Позиция: 8 ОШИБКА: отсутствует запись в предложении для таблицы «link» Позиция: 8 ОШИБКА: отсутствует запись в предложении для таблицы «link» Позиция: 8 »