Группа фильтров PostgreSQL по отдельным значениям

У меня есть запрос, который возвращает данные, как показано;

name | field | count_1 | count_2 |
-----|-------|---------|---------|
John |  aaa  |    3    |    3    |
John |  bbb  |    3    |    3    |
John |  ccc  |    3    |    3    |
John |  ddd  |    1    |    1    |
Dave |  aaa  |    3    |    3    |
Dave |  bbb  |    3    |    3    |
Dave |  ccc  |    3    |    3    |
Dave |  ddd  |    3    |    3    |
-----|-------|---------|---------|

Мне нужно отфильтровать эти данные по счетчикам, где count_1 и count_2 - это =3. В приведенном выше случае для Джона в поле ddd оба счетчика не соответствуют условию, поэтому запрос должен возвращать только Dave, независимо от других условий, выполняемых John в других полях. Как я могу этого добиться?

До тех пор, пока индивидуум не соответствует ни одному счету в данных полях, он должен быть отфильтрован.

Чтобы правильно понять, покажите в вопросе результат, который вы хотите получить

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

Ответы 3

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

Если я правильно понял, NOT EXISTS может вам помочь.

SELECT *
       FROM (<your query>) x
       WHERE NOT EXISTS (SELECT *
                                FROM (<your query) y
                                WHERE y.name = x.name
                                      AND (y.count_1 <> 3
                                           OR y.count_2 <> 3));

Замените <your query> вашим запросом, который дал вам опубликованный результат (или используйте для этого CTE, но имейте в виду, что это может вызвать проблемы с производительностью в Postgres).

Возможно, есть более элегантное решение, которое уже «сокращает» ваш запрос, но для его поиска потребуется дополнительная информация о вашей схеме и текущем запросе.

Спасибо. Это действительно помогло - хотя я изменил первую часть запроса, как в ответе Гордона (WITH t AS (<my-query>) SELECT * FROM t WHERE NOT EXISTS...), чтобы избежать повторения огромного запроса.

Clint_A 25.07.2018 15:49

@Clint_A. . . Учитывая, что вы используете подзапрос, вероятно, лучше иметь решение, которое ссылается на подзапрос только один раз.

Gordon Linoff 25.07.2018 15:57

Я думаю, ты хочешь:

with t as (
      <your query here>
     )
select t.*
from (select t.*,
             count(*) filter (where count_1 <> 3) over (partition by name) as cnt_1_3,
             count(*) filter (where count_2 <> 3) over (partition by name) as cnt_2_3
      from t
     ) t
where cnt_1_3 = 0 and cnt_2_3 = 0;

Если вам не нужны исходные строки, я бы пошел на агрегацию:

select name
from t
group by name
having min(count_1) = max(count_1) and min(count_1) = 3 and
       min(count_2) = max(count_2) and min(count_2) = 3;

Или вы можете сформулировать это так:

having sum( (count_1 <> 3)::int ) = 0 and
       sum( (count_2 <> 3)::int ) = 0

Обратите внимание, что все вышеизложенное предполагает, что счетчики не являются NULL (что кажется разумным для чего-то, что называется счетчиком). Вы можете использовать сравнение с безопасностью NULL (is distinct from), если значения NULL возможны.

Используйте логический агрегат bool_and() в предложении имеющий, чтобы получить имена, соответствующие условиям:

select name
from the_data
group by 1
having bool_and(count_1 = 3 and count_2 = 3)

 name 
------
 Dave
(1 row)

Вы можете использовать это как подзапрос для фильтрации и возврата исходных строк (если вам это нужно):

select *
from the_data
where name in (
    select name
    from the_data
    group by 1
    having bool_and(count_1 = 3 and count_2 = 3)
    )

 name | field | count_1 | count_2 
------+-------+---------+---------
 Dave | aaa   |       3 |       3
 Dave | bbb   |       3 |       3
 Dave | ccc   |       3 |       3
 Dave | ddd   |       3 |       3
(4 rows)    

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