Это может привести вас в правильном направлении. Во-первых, самая большая проблема заключается в том, что это вычисление выходит из-под контроля даже для небольшого числа предметов и / или групп.
Запрашиваемый мною запрос был написан для MySQL, и я уверен, что некоторые из них недоступны в SQL Server, но вы можете его адаптировать, я уверен. Мне пришлось перепрыгнуть через множество обручей, специфичных для MySQL, чтобы получить самую дешевую строку для каждой комбинации элементов. Из того, что я понимаю, на самом деле с MS SQL проще, так как кажется, что он поддерживает агрегатную функцию FIRST.
Кроме того, вы не указали, имеет ли смысл в вашей ситуации, чтобы кто-то получал несколько одинаковых предметов. Я предположил, что нет, но если вы удалите предложение, которое будет иметь кратные.
Центральная проблема заключается в том, что вам нужно создать все возможные комбинации групп, которые могут включать все покупаемые элементы. Для этого необходимо объединить таблицу recur_group с количеством покупаемых предметов. В моем примере запроса я включаю до 4-х самостоятельных объединений, которые охватывают все возможные комбинации до 4 элементов.
Если группы и цены меняются не так часто, вы можете сохранить результаты запроса в таблице, которая будет заполняться при каждом изменении ваших данных.
Суть в том, что вам, вероятно, нужно что-то упростить, если только у вас не будет достаточно небольшого количества групп и элементов.
set @type = '';
set @num = 1;
select item_list, total, g1, g2, g3, g4,
@num := if(@type = item_list, @num + 1, 1) as row_number,
@type := item_list as dummy
from (
select group_concat(i.item_code order by i.item_code separator ',')
as item_list,
( select sum(recur_amount)
from recur_group_item
where recur_group_id in (
perms.g1, perms.g2, perms.g3, perms.g4
)) as total,
perms.g1, perms.g2, perms.g3, perms.g4
from recur_item i
join recur_group_item gi
on gi.recur_item_id = i.recur_item_id
join (
select recur_group_id as g1,
null as g2, null as g3, null as g4
from recur_group
union
select g1.recur_group_id as g1, g2.recur_group_id as g2,
null as g3, null as g4
from recur_group g1, recur_group g2
where g1.recur_group_id < g2.recur_group_id
union
select g1.recur_group_id as g1, g2.recur_group_id as g2,
g3.recur_group_id as g3, null as g4
from recur_group g1, recur_group g2, recur_group g3
where g1.recur_group_id < g2.recur_group_id
and g2.recur_group_id < g3.recur_group_id
union
select g1.recur_group_id as g1, g2.recur_group_id as g2,
g3.recur_group_id as g3, g4.recur_group_id as g4
from recur_group g1, recur_group g2, recur_group g3, recur_group g4
where g1.recur_group_id < g2.recur_group_id
and g2.recur_group_id < g3.recur_group_id
and g3.recur_group_id < g4.recur_group_id
) as perms
on gi.recur_group_id in (perms.g1, perms.g2, perms.g3, perms.g4)
group by perms.g1, perms.g2, perms.g3, perms.g4
having count(i.item_code) = count(distinct i.item_code)
order by item_list asc, total asc
) as groupings
group by item_list, total, g1, g2, g3, g4
having row_number = 1;
Что, с немного расширенным набором данных, дает результаты, подобные этому:
item_list total g1 g2 g3 g4
----------------------------- ----- -- ------ ------ ------
apple 2.0 3 (null) (null) (null)
apple,banana 4.0 3 5 (null) (null)
apple,banana,onion 4.0 5 9 (null) (null)
apple,banana,onion,orange 5.0 2 9 (null) (null)
apple,banana,onion,pear 7.0 5 6 9 (null)
apple,banana,onion,pineapple 8.0 5 7 9 (null)
apple,banana,orange 3.0 1 (null) (null) (null)
apple,banana,orange,pear 6.0 1 6 (null) (null)
apple,banana,orange,pineapple 7.0 3 5 10 (null)
apple,banana,pear 7.0 3 5 6 (null)
apple,banana,pear,pineapple 11.0 3 5 6 7
apple,banana,pineapple 8.0 3 5 7 (null)
apple,onion 2.0 9 (null) (null) (null)
apple,onion,orange 4.0 4 9 (null) (null)
apple,onion,orange,pear 7.0 4 6 9 (null)
apple,onion,orange,pineapple 5.0 9 10 (null) (null)
apple,onion,pear 5.0 6 9 (null) (null)
apple,onion,pear,pineapple 9.0 6 7 9 (null)
apple,onion,pineapple 6.0 7 9 (null) (null)
apple,orange 4.0 3 4 (null) (null)
apple,orange,pear 7.0 3 4 6 (null)
apple,orange,pear,pineapple 8.0 3 6 10 (null)
apple,orange,pineapple 5.0 3 10 (null) (null)
apple,pear 5.0 3 6 (null) (null)
apple,pear,pineapple 9.0 3 6 7 (null)
apple,pineapple 6.0 3 7 (null) (null)
banana 2.0 5 (null) (null) (null)
banana,onion 8.0 5 8 (null) (null)
banana,onion,orange 9.0 2 8 (null) (null)
banana,onion,orange,pear 12.0 2 6 8 (null)
banana,onion,orange,pineapple 11.0 5 8 10 (null)
banana,onion,pear 11.0 5 6 8 (null)
banana,onion,pear,pineapple 15.0 5 6 7 8
banana,onion,pineapple 12.0 5 7 8 (null)
banana,orange 3.0 2 (null) (null) (null)
banana,orange,pear 6.0 2 6 (null) (null)
banana,orange,pear,pineapple 8.0 5 6 10 (null)
banana,orange,pineapple 5.0 5 10 (null) (null)
banana,pear 5.0 5 6 (null) (null)
banana,pear,pineapple 9.0 5 6 7 (null)
banana,pineapple 6.0 5 7 (null) (null)
onion 6.0 8 (null) (null) (null)
onion,orange 8.0 4 8 (null) (null)
onion,orange,pear 11.0 4 6 8 (null)
onion,orange,pear,pineapple 12.0 6 8 10 (null)
onion,orange,pineapple 9.0 8 10 (null) (null)
onion,pear 9.0 6 8 (null) (null)
onion,pear,pineapple 13.0 6 7 8 (null)
onion,pineapple 10.0 7 8 (null) (null)
orange 2.0 4 (null) (null) (null)
orange,pear 5.0 4 6 (null) (null)
orange,pear,pineapple 6.0 6 10 (null) (null)
orange,pineapple 3.0 10 (null) (null) (null)
pear 3.0 6 (null) (null) (null)
pear,pineapple 7.0 6 7 (null) (null)
pineapple 4.0 7 (null) (null) (null)