SQL-запрос, касающийся того, сколько из каждого набора наборов имеет данный потребитель - PullRequest
0 голосов
/ 09 мая 2018

Скажем, у меня есть клиенты, которым могут быть присуждены определенные призы:

SELECT gs.claimed_by AS consumer_id, p.prize_id AS prize_id FROM 
  awarded_prizes

И прямо сейчас, у клиента 1 есть три приза, а у клиента 2 - один приз

+-------------+----------+
| consumer_id | prize_id |
+-------------+----------+
|           1 |       45 |
|           1 |       46 |
|           1 |       47 |
|           2 |       66 |
+-------------+----------+

Скажем, у нас также есть коллекции, и если вы соберете всех участников этого предмета коллекционирования, у вас теперь есть коллекционный набор:

SELECT set_id, member_prize_id AS prize_id FROM collectable_set_members;
+--------+----------+
| set_id | prize_id |
+--------+----------+
|      1 |       45 |
|      1 |       46 |
|      1 |       47 |
|      2 |       65 |
|      2 |       66 |
+--------+----------+

Используя приведенную выше таблицу и предыдущий запрос, мы видим, что клиент 1 выполнил набор 1 один раз (у него 45, 46, 47), а клиент 2 ничего не выполнил.

Существуют случаи, когда клиент может выполнить набор несколько раз (клиент может иметь 45, 46, 47, 45, 46, 47 в таблице won_prize.

Я смотрел на проблему кладовая и ее варианты (например, проблему бармена), играл с перекрестными соединениями и группировками и, похоже, не могу найти то, что я хочу.

Я пытаюсь получить результат для данного клиента, показывая все set_ids, которыми они владеют, и количество выполненных им наборов:

+-------------+---------------+--------+
| consumer_id | completed_set |  count |
+-------------+---------------+--------+
|           1 |             1 |      1 |
+-------------+---------------+--------+ 

Я на mariadb: 5,5

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

Для чего я стою, я придумал хорошую процедуру для этого в Sql Server. Это работает даже в том случае, если в каждом наборе есть перекрывающиеся значения приз_ид (по умолчанию используется более высокий коэффициент, если он неоднозначный). Предположим, что все временные таблицы являются исходными данными:

declare @awarded_prize table (rowid int identity, consumer_id int, prize_id int )
insert @awarded_prize
select * from #awarded_prizes

declare @collections table ( set_id int, prize_id int, rownumber int , filled int)
insert @collections
select *, row_number() over(partition by set_id order by set_id, prize_id) , null
from #collections

declare @todelete table (rowid int)
declare @scorecard table (consumer_id int, set_id int)

declare @iterator int=1
declare @prize_id int
declare @set_id int = (Select min(set_id) from @collections)
declare @consumer_id int = (Select min(consumer_id) from @awarded_prize)
while @consumer_id<=(select max(consumer_id) from @awarded_prize)
    begin
    while @set_id<=(select max(set_id) from @collections)
      begin
        while 1=1
        begin
        select @prize_id=prize_id 
        from @collections 
        where set_id=@set_id and rownumber=@iterator


        if (select max(rowid) from @awarded_prize where prize_id=@prize_id and consumer_id=@consumer_id and rowid not in (select rowid from @todelete)) is null break
        insert @todelete
        select max(rowid) from @awarded_prize where prize_id=@prize_id and consumer_id=@consumer_id and rowid not in (select rowid from @todelete)

        update @collections set filled=1 
        where rownumber=@iterator and set_id=@set_id

        if not exists(select 1 from @collections where set_id=@set_id and filled is null)
        begin
            insert @scorecard
            select @consumer_id, @set_id
            delete @awarded_prize where rowid in (Select rowid from @todelete) 
            delete @todelete
            update @collections set filled=null where filled=1
        end
        set @iterator=case when @iterator=(Select max(rownumber) from @collections where set_id=@set_id) then 
        (select min(rownumber) from @collections where set_id=@set_id) else @iterator+1 end 
      end
      delete @todelete
      set @iterator=1
      set @set_id=@set_id+1
    end
    set @iterator=1
    select @set_id=min(set_id) from @collections
    select @consumer_id=min(consumer_id) from @awarded_prize where consumer_id>@consumer_id
    end

    select consumer_id, set_id, count(*) complete_sets 
    from @scorecard
    group by consumer_id, set_id
    order by consumer_id, set_id
0 голосов
/ 09 мая 2018

Не могу понять, что должен означать ваш последний столбец 'count', но вот решение, в котором перечислены пользователи и их наборы завершены.

демо-ссылка

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

Я знаю, что это mssql, но мне не удалось заставить работать mysql ctes в sqfiddle. CTE-s - это не более чем подзапрос. Если ваш сервер не поддерживает CTE, вы можете вместо этого использовать обычные подзапросы или временные таблицы.

0 голосов
/ 09 мая 2018

Смотрите здесь SqlFiddle

Мои таблицы имеют имена, отличные от ваших, но это доказывает:

select sets_x_consumers.consumer_id, sets_x_consumers.set_id, 
  set_summary.items_in_set = consumer_summary.items_per_set_per_consumer as set_is_complete
from (
  -- build a cross-product of sets and consumers
  select distinct set_id, consumer_id
  from sets join consumers -- no join condition -> cross product
) sets_x_consumers 
inner join
( -- the total number of items in each set per set_id
  select set_id, count(*) items_in_set
  from sets 
  group by set_id
) set_summary on sets_x_consumers.set_id = set_summary.set_id
inner join
( -- the total number of items per set and customer 
  select set_id, consumer_id, count(*) items_per_set_per_consumer
  from sets 
  inner join consumers on sets.prize_id = consumers.prize_id
  group by consumer_id, set_id
) consumer_summary on sets_x_consumers.set_id = consumer_summary.set_id and sets_x_consumers.consumer_id = consumer_summary.set_id

Моя основная идея - суммировать количество предметов в каждом наборе и количество предметов в наборе, которое потребовал каждый потребитель. Пока не существует дублирующих записей для пары потребителя и приза, это должно работать (если дубликаты были разрешены, я бы использовал count distinct(prize_id) для consumer_summary).

Результат запроса выше:

| consumer_id | set_id | set_is_complete |
|-------------|--------|-----------------|
|           1 |      1 |               1 |
|           2 |      2 |               0 |

Здесь указывается каждая пара потребителей и набор, для которого у потребителя есть хотя бы один приз. (чтобы изменить это, чтобы перечислить каждую комбинацию набора потребителей, используйте outer join)

На этой основе должно быть легко перечислить только полные наборы или суммировать количество полных наборов; -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...