Есть ли альтернатива WHERE COUNT () с оконной функцией в PostgreSQL? - PullRequest
0 голосов
/ 06 августа 2020

Я пытаюсь выполнить группировку по двум столбцам и отфильтровать результат только по записям, у которых нет дублированного первого столбца. Затем полученные значения можно использовать как КЛЮЧ и ЗНАЧЕНИЕ соответственно. Я добился желаемого результата двумя разными способами, но ни один из них не кажется подходящим.

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

create table example (
    foreign_key integer,
    item_value text
);

insert into example (foreign_key, item_value) values 
(1, 'a'), (1, 'a'), (1, 'b'), (1, 'a'), (2, 'a'), (2, 'a'), (2, 'a'), 
(3, 'c'), (3, 'a'), (3, 'a'), (4, 'a'), (4, 'c'), (4, 'e'), (5, 'b');

Первый способ - использование CTE и предложения WITH, затем фильтрация с помощью подзапроса в предложении WHERE:

with grouped AS (
    select
        foreign_key,
        item_value 
    from
        example 
    group by
        1, 2 
    order by
        1 -- ordering only to view in case of running individually.
)
select
    * 
from
    grouped g 
where
    (
        select
            count(foreign_key)
        from
            grouped
        where
            foreign_key = g.foreign_key
    ) = 1;

Второй способ - использование подзапроса с окном OVER функция в предложении FROM:

select
    foreign_key,
    item_value 
from
    (
        select
            *,
            count(foreign_key) over( partition by foreign_key ) as n 
        from
            example 
        group by
            1, 2 
    ) t 
where
    t.n = 1;

Оба способа возвращают тот же результат, с учетом используемых входных данных:

foreign_key item_value
2   "a"
5   "b"

Но они кажутся слишком дорогими, кроме того, так приятно читать.

Есть ли лучший способ добиться того же результата?

Ответы [ 3 ]

2 голосов
/ 06 августа 2020

Кажется, это простая группа с подсчетом различных значений:

select foreign_key, max(item_value) as item_value
from example
group by foreign_key
having count(distinct item_value) = 1
order by foreign_key;

Онлайн-пример

0 голосов
/ 06 августа 2020

Я бы ожидал чего-то вроде:

select e.*
from (select e.*, count(*) over (partition by foreign_key) as cnt
      from example e
     ) e
where cnt = 1;

Однако возможен и метод агрегирования. Было бы интересно проверить, что быстрее.

Альтернативой, если строки гарантированно уникальны, будет not exists:

select e.*
from example e
where not exists (select 1
                  from example e2
                  where e2.foreign_key = e.foreign_key and e2.value <> e.value
                 );

Оба эти метода позволяют легко возвращать все столбцы в данной строке.

0 голосов
/ 06 августа 2020

Вы можете попробовать с exists

 select distinct foreign_key,item_value
    from example e where exists (select 1 from example e1 where e.foreign_key=e1.foreign_key having count(distinct item_value)=1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...