powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Выборка связных таблиц с тегами
8 сообщений из 8, страница 1 из 1
Выборка связных таблиц с тегами
    #39434331
ambasador
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Две таблицы:

(Relationship)
video_id | tag_id
------------------
1 | 1
1 | 2
2 | 1

(Tags)
id | tag_name
--------------------
1 | Action
2 | Strategy

Нужно получить выборку video_id из таблицы Relationship где присутствуют оба тега и "Action" и "Strategy". Поэтому video_id = 2 точно не должен быть в выборке.
Вобщем делаю такой запрос:
select * from relationship a left join tags b on a.tag_id = b.id
where b.tag_name in('Action', 'Strategy');
У меня выводятся все три строки что неверно, вобщем то понятно что in предполагает любое из этих тегов, необходимо сделать проверку по AND.
...
Рейтинг: 0 / 0
Выборка связных таблиц с тегами
    #39434449
ambasador
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нашел вот это:
Код: plsql
1.
2.
3.
4.
select * from relationship a
inner join tags t1 on t1.id = a.tag_id
inner join tags t2 on t2.id = a.tag_id
where t1.tag_name = 'Action' and t2.tag_name = 'Strategy';


Запрос возвращает пустую выборку
...
Рейтинг: 0 / 0
Выборка связных таблиц с тегами
    #39434487
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ambasador,

Код: plaintext
1.
2.
ВЫБРАТь * ИЗ связи
где СУЩЕСТВУЕТ (ВЫБРАТЬ 1 из тегов КОТОРЫЕ 'Action')
И СУЩЕСТВУЕТ (ВЫБРАТЬ 1 из тегов КОТОРЫЕ 'Strategy')

а вообщето именно для тегов в силу произвольности набора, [иногда] удобнее пользоваться такими фичами пж как поля--массивы, tags_ids int[] прямо в таблице видео, и соответствующими индексами .
подробнее -- к Бартунову и ко. они на индексированиях всякой нерелятивистики собак.. вполне себе корейцы.

если теги каждого видео обновляются редко, ессно
в противном случае может быть очень больно, почти как у убера
...
Рейтинг: 0 / 0
Выборка связных таблиц с тегами
    #39434493
ambasador
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
qwwq,
Ну вот вобщем у меня получилось примерно такое:
Код: plsql
1.
2.
3.
4.
select a1.video_id from relationship a1
where tag_id in (select id from tag where tag_name in ('Action', 'Strategy'))
group by a1.video_id
having count(*) = 2;


Здесь видимо "having count(*) = 2" позволяет выводить только сгруппированные по два video_id строки это и будут видео которые и в 'Action' и в 'Strategy' тегах, запрос жестко завязан, но он работает :), вы про эту боль - что при добавлении тега в фильтрацию нужно еще и кол-во счетчика увеличить?
А с джойнами у меня так и не получилось реализовать.
...
Рейтинг: 0 / 0
Выборка связных таблиц с тегами
    #39434495
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ambasador,

да, что-то я совсем левое наплёл.
надо было стартовать от видео, и т.п. (т.е. выбрать видео, для которых несколько exists
()-ов...)
ну да не суть.


всё примерно так, как вы написали, но проще не каунты считать, а содержимость ключей в array_agg(tag_id). для этого операторы пересечения/вхождения массивов существует
...
Рейтинг: 0 / 0
Выборка связных таблиц с тегами
    #39434501
PgSQLanonymous3
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ambasadorqwwq,
Ну вот вобщем у меня получилось примерно такое:
Код: plsql
1.
2.
3.
4.
select a1.video_id from relationship a1
where tag_id in (select id from tag where tag_name in ('Action', 'Strategy'))
group by a1.video_id
having count(*) = 2;



Подобный вариант:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
WITH SelectedTags AS (
SELECT id
  FROM tags
 WHERE tag_name IN ('Action', 'Strategy')
)
SELECT *
  FROM Relationship AS r
 WHERE (SELECT COUNT(*)
          FROM Relationship AS r1
         WHERE r1.video_id = r.video_id
           AND r1.tag_id IN (SELECT id FROM SelectedTags)
        ) = (SELECT COUNT(*) FROM SelectedTags);



qwwqнадо было стартовать от видео, и т.п. (т.е. выбрать видео, для которых несколько exists()-ов...)
ну да не суть.

А это, наверное, как-то так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
SELECT *
  FROM relationship AS r
 WHERE EXISTS (
	  SELECT 1
	    FROM relationship AS re
            JOIN tags AS t
	      ON t.id = re.tag_id
	   WHERE re.video_id = r.video_id AND t.tag_name = 'Action'
       )
   AND EXISTS (
	  SELECT 1
	    FROM relationship AS re
            JOIN tags AS t
	      ON t.id = re.tag_id
	   WHERE re.video_id = r.video_id AND t.tag_name = 'Strategy'
       );


qwwqвсё примерно так, как вы написали, но проще не каунты считать, а содержимость ключей в array_agg(tag_id). для этого операторы пересечения/вхождения массивов существует
А это примерно так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT video_id, tag_id
  FROM (
       SELECT *, ARRAY_AGG(tag_id) OVER (PARTITION BY video_id) AS tags
         FROM Relationship
       ) AS video_tags
 WHERE tags @> (SELECT ARRAY_AGG(id)
                  FROM tags
                WHERE tag_name IN ('Action', 'Strategy')
               )
...
Рейтинг: 0 / 0
Выборка связных таблиц с тегами
    #39434517
ambasador
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо за обилие примеров, подобное как раз не так давно нашел на stackoverflow.com , и эта проблема похоже называется "relational division"
...
Рейтинг: 0 / 0
Выборка связных таблиц с тегами
    #39434557
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PgSQLanonymous3
спасибо , добрый человек
немного поясню,, что думал я
PgSQLanonymous3А это, наверное, как-то так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
SELECT *
  FROM video AS v -- таки само видео, а не связи
 WHERE EXISTS (
	  SELECT 1
	    FROM relationship AS re
            JOIN tags AS t
	      ON t.id = re.tag_id
	   WHERE re.video_id = v.video_id AND t.tag_name = 'Action'
       )
   AND EXISTS (
	  SELECT 1
	    FROM relationship AS re
            JOIN tags AS t
	      ON t.id = re.tag_id
	   WHERE re.video_id = v.video_id AND t.tag_name = 'Strategy'
       );


qwwqвсё примерно так, как вы написали, но проще не каунты считать, а содержимость ключей в array_agg(tag_id). для этого операторы пересечения/вхождения массивов существует
А это примерно так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
SELECT video_id --, tags
  FROM (
       SELECT video_id, ARRAY_AGG(tag_id) AS tags
         FROM Relationship
/*         WHERE tag_id IN(SELECT tag_id
                                       WHERE tag_name =ANY(ARRAY['Action', 'Strategy'])
*/ -- оптимизация для реляционной структуры, если тегов в среднем 100-ни
       GROUP BY video_id 
       ) AS video_tags     -- а это 
                                      --сама таблица видео с массивным полем тагов, вместо 1--N
 WHERE tags @> (SELECT ARRAY_AGG(id)
                  FROM tags
                WHERE tag_name =ANY(ARRAY['Action', 'Strategy'])
                                            -- один массивный параметр
               )
-- т.е. скорее болванка для альтернативного способа
-- хранения связей в массивах при видео
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Выборка связных таблиц с тегами
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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