powered by simpleCommunicator - 2.0.40     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
25 сообщений из 92, страница 1 из 4
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078020
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доброго вечера,подскажите пожалуйста как сделать запрос
типо такого

Код: plsql
1.
select distinct p.* from person p  join person_channel pc on p.id = pc.person_id where  pc.channel_type =all of this-> ('SMS' ,'PUSH');



Нужно чтобы в результирующем наборе были только те записи,чей channel_type удовлетворяет строго всем типам из входящих аргументов,а не одному из
как было бы в случае с таким запросом
Код: plsql
1.
select distinct p.* from person p  join person_channel pc on p.id = pc.person_id where  pc.channel_type  in ('SMS' ,'PUSH')
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078121
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79
Доброго вечера,подскажите пожалуйста как сделать запрос
типо такого

Код: plsql
1.
select distinct p.* from person p  join person_channel pc on p.id = pc.person_id where  pc.channel_type =all of this-> ('SMS' ,'PUSH');



Нужно чтобы в результирующем наборе были только те записи,чей channel_type удовлетворяет строго всем типам из входящих аргументов,а не одному из
как было бы в случае с таким запросом
Код: plsql
1.
select distinct p.* from person p  join person_channel pc on p.id = pc.person_id where  pc.channel_type  in ('SMS' ,'PUSH')



из вашего не очень понятного описания я бы предположил такой вариант

Код: sql
1.
2.
3.
4.
5.
select p.* from person p 
where 
exists (select from person_channel pc where p.id = pc.person_id and pc.channel_type='SMS')
and
exists (select from person_channel pc where p.id = pc.person_id and pc.channel_type='PUSH');




--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078167
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,
такой вариант не подойдет,так как на вход в фильтр подается список значений
тоесть в результирующем наборе должны быть только те записи,которые имеют все перечисленные в списке типы и заранее никто не знает количество элементов в этом списке ,только тип - строка.

Код: plsql
1.
select distinct p.* from person p  join person_channel pc on p.id = pc.person_id where  pc.channel_type = have all of these elements (:list );
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078170
Фотография court
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79
на вход в фильтр подается список значений
как выглядит этот список ?
Это строка типа
Код: sql
1.
'''SMS'' ,''PUSH'''

?
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078172
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
court
asv79
на вход в фильтр подается список значений
как выглядит этот список ?
Это строка типа
Код: sql
1.
'''SMS'' ,''PUSH'''

?

нет,это набор строковых значений- передается из java в формате List<String>
тоесть будет
Код: plsql
1.
'SMS','PUSH','EMAIL'.....,etc
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078174
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сейчас я изобразил вот такой вариант
Код: plsql
1.
2.
3.
select  p.* from respondent p  join respondent_channel rc on p.id = rc.respondent_id where  rc.channel_type = any(string_to_array(:some_list,','))
group by p.id
having count(distinct rc.channel_type )=array_length(string_to_array(:some_list,','),1);



где на вход будет подаваться 'SMS,PUSH,EMAIL,....etc' в виде строки

но мне это не очень подходит изза постфильтра - записей достаточно много и тащить их все из бд,затем накладывать having не очень хорошая идея ну и конечно не хочется преобразоывать список в строку типа 'SMS,PUSH,EMAIL,....etc' - проблем с этим нет,но это тоже не очень привествуется
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078177
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79
Maxim Boguk,
такой вариант не подойдет,так как на вход в фильтр подается список значений
тоесть в результирующем наборе должны быть только те записи,которые имеют все перечисленные в списке типы и заранее никто не знает количество элементов в этом списке ,только тип - строка.

Код: plsql
1.
select distinct p.* from person p  join person_channel pc on p.id = pc.person_id where  pc.channel_type = have all of these elements (:list );



Какие то проблемы сгенерировать нужное количество EXISTS в запросе?
Основной вопрос - вам вообще на производительность запроса наплевать?

Если на скорость работы наплевать то вариантов много можно придумать конечно.
Если нет то вариант с N exits будет скорее всего самым быстрым.

Ну и вопрос вам вообще что хочется - минимальный обьем програмирования или максимальная производительность в целом?


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078178
Alexander A. Sak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вариант с exists выглядит очень даже.
Просто в джава-коде надо пришедший список с channel_type не передавать в запрос как есть, а для каждого элемента делать and exists в запросе.
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078181
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk
asv79
Maxim Boguk,
такой вариант не подойдет,так как на вход в фильтр подается список значений
тоесть в результирующем наборе должны быть только те записи,которые имеют все перечисленные в списке типы и заранее никто не знает количество элементов в этом списке ,только тип - строка.

Код: plsql
1.
select distinct p.* from person p  join person_channel pc on p.id = pc.person_id where  pc.channel_type = have all of these elements (:list );



Какие то проблемы сгенерировать нужное количество EXISTS в запросе?
Основной вопрос - вам вообще на производительность запроса наплевать?

Если на скорость работы наплевать то вариантов много можно придумать конечно.
Если нет то вариант с N exits будет скорее всего самым быстрым.

Ну и вопрос вам вообще что хочется - минимальный обьем програмирования или максимальная производительность в целом?


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

производительность на первом месте ,подскажите пожалуйста как это будет выглядеть с генерацией EXISTS при условии что будет подаваться на вход List<String> либо вы предлагаете сделать это в джава коде?в джава коде проблем вроде быть не должно с этим спасибо за идею
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078184
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Предполагаю, что channel_type буквально десяток в прыжке разных. Если есть уникальный индекс person_channel (person_id, channel_type) то можно сделать

Код: sql
1.
2.
3.
select p.* from person p 
where 
exists (select from person_channel pc where p.id = pc.person_id and pc.channel_type in ('SMS' ,'PUSH') limit 1 offset 1)


offset по числу значений в списке -1
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078199
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Melkij
Предполагаю, что channel_type буквально десяток в прыжке разных. Если есть уникальный индекс person_channel (person_id, channel_type) то можно сделать

Код: sql
1.
2.
3.
select p.* from person p 
where 
exists (select from person_channel pc where p.id = pc.person_id and pc.channel_type in ('SMS' ,'PUSH') limit 1 offset 1)


offset по числу значений в списке -1

супер работает все отлично
а можно обьяснить принцип по которому данный запрос отрабатывает - я смотрю на него и не очень врубаюсь-тоесть сначала он находит те записи в которых есть хотя бы одно значение из списка ,потом смотрит число вхождений по офсету и выдает совпадение наверх?
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078205
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Melkij
Предполагаю, что channel_type буквально десяток в прыжке разных. Если есть уникальный индекс person_channel (person_id, channel_type) то можно сделать

Код: sql
1.
2.
3.
select p.* from person p 
where 
exists (select from person_channel pc where p.id = pc.person_id and pc.channel_type in ('SMS' ,'PUSH') limit 1 offset 1)


offset по числу значений в списке -1

а что по производительности? если в таблице будет миллион персон это будет 1 млн подзапросов?
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078220
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Melkij
Предполагаю, что channel_type буквально десяток в прыжке разных. Если есть уникальный индекс person_channel (person_id, channel_type) то можно сделать

Код: sql
1.
2.
3.
select p.* from person p 
where 
exists (select from person_channel pc where p.id = pc.person_id and pc.channel_type in ('SMS' ,'PUSH') limit 1 offset 1)


offset по числу значений в списке -1

по аналитике не очень этот запрос даже на 800 персонах и всего 10 каналах 2 мс время выполнения
правда planning time 0.277

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Seq Scan on respondent p  (cost=0.00..1870.24 rows=402 width=209) (actual time=0.186..2.018 rows=2 loops=1)
  Filter: (SubPlan 1)
  Rows Removed by Filter: 802
  SubPlan 1
    ->  Limit  (cost=1.15..2.30 rows=1 width=0) (actual time=0.002..0.002 rows=0 loops=804)
          ->  Seq Scan on respondent_channel rc  (cost=0.00..1.15 rows=1 width=0) (actual time=0.002..0.002 rows=0 loops=804)
"                Filter: ((channel_type = ANY ('{PUSH,SMS}'::text[])) AND (p.id = respondent_id))"
                Rows Removed by Filter: 10
Planning Time: 0.277 ms
Execution Time: 2.089 ms
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078263
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79,
В ветке по бд все равно что там у вас в java.
Вам надо либо сгенерить строку в in.
Либо передать таблицу list в хранимку
Либо сгенерить временную таблу в сессии бд и заджойнить ее с основной.
Смотрите по нагрузочному тесту.
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078286
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79
а можно обьяснить принцип по которому данный запрос отрабатывает - я смотрю на него и не очень врубаюсь-тоесть сначала он находит те записи в которых есть хотя бы одно значение из списка ,потом смотрит число вхождений по офсету и выдает совпадение наверх?

при наличии уникального индекса при условии in (N элементов) после offset N-1 может остаться строка только в том случае, если каждый из N элементов присутствует в выборке. Если хоть даже одно нет - то offset всё проглотит, 0 строк в подзапросе, получим exists() = false

asv79
по аналитике не очень этот запрос даже на 800 персонах и всего 10 каналах 2 мс время выполнения

Добавьте данных. Ну миллионов 10 строк хотя бы.
На таких "объёмах" не имеет смысла ничего смотреть. Если же вам важны именно доли мс и 2мс уже медленно - то клиент-серверные субд вам вовсе не подходят. Латентность сети уже больше времени выполнения самих запросов получается.

asv79
если в таблице будет миллион персон это будет 1 млн подзапросов?

А зачем вам может понадобиться считать быстро весь миллион персон?
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078290
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Melkij,
+1 абстрактное время ни о чем не говорит. Да еще без реального набора данных по ТЗ.
Самой проблемы пока не видно.
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078295
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PetroNotC Sharp,
на надо ничего там никуда джоинить и тд

Код: plsql
1.
2.
3.
select  p.* from respondent p where
  exists(select from respondent_channel rc where p.id = rc.respondent_id and   rc.channel_type ='SMS') and
  exists(select from respondent_channel rc where p.id = rc.respondent_id and   rc.channel_type ='PUSH')


динамически буду строить такой запрос в зависимости от количества элементов в ходящем списке и получаю

вот такие показатели и что не маловажно в других запросах идет seq сканироание ,в этом же примере оно идесное

собственно время меня удовлетворяет и я выберу этот вариант

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
Nested Loop Semi Join  (cost=1.54..9.65 rows=1 width=209) (actual time=0.101..0.115 rows=2 loops=1)
  ->  Nested Loop  (cost=1.40..9.45 rows=1 width=217) (actual time=0.067..0.076 rows=2 loops=1)
        ->  HashAggregate  (cost=1.13..1.14 rows=1 width=8) (actual time=0.030..0.032 rows=2 loops=1)
              Group Key: rc.respondent_id
              Batches: 1  Memory Usage: 24kB
              ->  Seq Scan on respondent_channel rc  (cost=0.00..1.12 rows=1 width=8) (actual time=0.021..0.022 rows=2 loops=1)
                    Filter: (channel_type = 'SMS'::text)
                    Rows Removed by Filter: 8
        ->  Index Scan using respondent_pkey on respondent p  (cost=0.28..8.29 rows=1 width=209) (actual time=0.019..0.019 rows=1 loops=2)
              Index Cond: (id = rc.respondent_id)
  ->  Index Only Scan using respondent_id_channel on respondent_channel rc_1  (cost=0.14..0.17 rows=1 width=8) (actual time=0.017..0.017 rows=1 loops=2)
        Index Cond: ((respondent_id = p.id) AND (channel_type = 'PUSH'::text))
        Heap Fetches: 2
Planning Time: 0.389 ms
Execution Time: 0.241 ms
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078300
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79,
>на надо ничего там никуда джоинить и тд
= странный вы.
Вам дали 4 варианта решения.
Джойнить был 4ый.
Вы ВЗЯЛИ ПЕРВЫЙ и сказали "не надо ничего там...
))))) LOL
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078301
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79,
>собственно время меня удовлетворяет и я выберу этот вариант
= выше вам написали, что записей надо поболее. Но вам виднее.
Проблем нет.
Удачи!
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078306
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Melkij


asv79
если в таблице будет миллион персон это будет 1 млн подзапросов?

А зачем вам может понадобиться считать быстро весь миллион персон?

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

речь вот про этот ваш запрос
Код: java
1.
2.
select  p.* from respondent p where
 exists(select from respondent_channel rc where p.id = rc.respondent_id and   rc.channel_type in (:some_list) limit 1 offset 2)
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078307
Фотография asv79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PetroNotC Sharp
asv79,
>собственно время меня удовлетворяет и я выберу этот вариант
= выше вам написали, что записей надо поболее. Но вам виднее.
Проблем нет.
Удачи!

Так я из того что вы написали вообще ничего не понял
вот это например ->надо либо сгенерить строку в in
Я понял что вы хотите чтобы я из списка сделал строку типо 'SMS,EMAIL....etc'
это не проблема ,а где запрос сам куда это подставить?
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078324
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79,
Дак зачем если ничего не понял отвечать словом НЕТ?
))))
Первый пункт это динамический sql
Склеиваешь любой запрос.
Или в in условие
Или
Куски подзапросов
Код: sql
1.
2.
3.
select  p.* from respondent p where
  exists(select from respondent_channel rc where p.id = rc.respondent_id and   rc.channel_type ='SMS') and
  exists(select from respondent_channel rc where p.id = rc.respondent_id and   rc.channel_type ='PUSH')


И так далее.
Можно и вьюху генерить на событие вставки записи.
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078325
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asv79,
Пятый вариант триггер поставить и перечень SMS,EMAIL....etc' будет всегда автоматом в табле person
Смотря что по бизнесу надо. OLAP/OLTP
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078901
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Так еще можно попробовать.

Код: sql
1.
2.
3.
4.
5.
create materialized view sms_push_respondents 
as
select  p.* from respondent p where
  exists(select from respondent_channel rc where p.id = rc.respondent_id and   rc.channel_type ='SMS') and
  exists(select from respondent_channel rc where p.id = rc.respondent_id and   rc.channel_type ='PUSH');
...
Рейтинг: 0 / 0
Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
    #40078908
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk

... вариант с N exits будет скорее всего самым быстрым.


это сомнительное утверждение для произвольного N
До какого-то порога (допустим, N ~ 7-8) так и будет.
Потом я бы ожидал перехода первенства к какому-то другому варианту.
Но не факт, что оказавшийся следующим победителем, сохранит лидерство для "слишком больших" N и person_channel

Код: sql
1.
2.
3.
4.
5.
select p.* from person p 
where 
exists (select from person_channel pc where p.id = pc.person_id and pc.channel_type='SMS')
and
exists (select from person_channel pc where p.id = pc.person_id and pc.channel_type='PUSH');



здесь exists может либо использоваться в качестве фильтра, либо преобразуется в join
В первом случае быстрее начнут "отдаваться строки", во втором, по вероятности, запрос в целом отработает быстрее,
при наличии подходящих индексов.

Смотрите, функционально этот запрос эквивалентен такому:
(а при трансформации в джойн как-то так и будет, с точностью до перестановки порядка таблиц)
Код: sql
1.
2.
3.
4.
5.
6.
select p.* from person p 
where 
exists (select from person_channel pc1, person_channel pc2 
          where p.id = pc1.person_id and pc1.channel_type='SMS'
            and  pc2.person_id =pc1.person_id and pc2.channel_type='PUSH'
)


тогда при добавлении третьего элемента поиска получается вот что:
Код: sql
1.
2.
3.
4.
5.
6.
7.
select p.* from person p 
where 
exists (select from person_channel pc1, person_channel pc2, person_channel pc3 
          where p.id = pc1.person_id and pc1.channel_type='SMS'
            and  pc2.person_id =pc1.person_id and pc2.channel_type='PUSH'
            and  pc3.person_id =pc2.person_id and pc3.channel_type='EMAIL'
)


Даже при наличии индексов, деградация производительности такого соединения по мере роста списка поиска,
растёт достаточно быстро, чтобы проиграть, в конце концов, какому-то из альтернативных вариантов.
Скорее всего, построенному на группировке тем или иным способом....
имхо...

PS (типа, в коллекцию)
среди вариантов записи реляционного деления встречается и вариант, который в данном случае мог бы быть выписан в таком роде:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select p.* from person p 
where 
p.id not in (
      select person_id 
      from (
        select p.id as person_id, channel_type 
        from person p, unnest(array['SMS', 'PUSH', 'EMAIL']) channel(channel_type)
        except 
        select pc.person_id, pc.channel_type  
        from person_channel pc 
      )
    )


визуально он не похож на многообещающий в плане производительности.
Хотя, на средних размерах данных и средней длине списка, может оказаться не сильно и хуже прочих.
...
Рейтинг: 0 / 0
25 сообщений из 92, страница 1 из 4
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Селект с фильтром,который выдаст только те записи котороые удовлетворяют условию
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]