Помогите с SQL Query, это возможно? - PullRequest
1 голос
/ 14 сентября 2010

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

MEMBER_RECUR_GROUP
member_id (PK)
recur_group_id (PK)

RECUR_GROUP
recur_group_id (PK)

RECUR_GROUP_ITEM
recur_group_id (PK)
recur_item_id (PK)
recur_amount

RECUR_ITEM
recur_item_id (PK)
ITEM_CODE
recur_term

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

Например, допустим, у нас есть 3 простых элемента: яблоко, апельсин и банан. Может быть повторяющаяся группа, содержащая все 3 (отдельные цены на товары в этой группе были бы самыми дешевыми, скажем, 1 доллар каждая). Также может быть повторяющаяся группа всего для 2 предметов, например, апельсина и банана. И может быть рекурсивная группа только для яблока (это отдельная цена, скажем, 2 доллара, будет выше, чем «упакованная» цена в других группах), другая - просто апельсин, а другая - просто банан.

Учитывая member_id и один или несколько item_codes (вероятно, CSV, что-то вроде «apple, banana»), я бы хотел запросить возвращение recur_term и recur_amount для каждого item_code из recur_group, которая содержит все item_codes. Если не существует recur_group, которая содержит все элементы, то должны быть возвращены значения recur_term и recur_amount из отдельной recur_group для отдельных элементов. Этого можно достичь за один запрос?

Я использую SQL Server 2005, если реализация имеет значение. Спасибо!

Вот примерные данные с ожидаемым результатом ниже.

MEMBER_RECUR_GROUP
1, 1

1, 3
1, 4
1, 5

RECUR_GROUP
1
2
3
4
5

RECUR_GROUP_ITEM
1, 1, 1,00
1, 2, 1,00
1, 3, 1,00

2, 2, 1,50
2, 3, 1,50

3, 1, 2,00
4, 2, 2,00
5, 3, 2,00

RECUR_ITEM
1, яблоко, 3
2, оранжевый, 3
3, банан, 3

Если для идентификатора участника 1 автоматически выставляется счет за яблоко, апельсин и банан, используется цена для повторного идентификатора группы 1.
Если для идентификатора участника 1 автоматически выставляется счет за яблоко и апельсин, используется комбинированная цена для повторяющихся групп с идентификаторами 3 и 4. (Поскольку член ID 1 не имеет повторяющейся группы с яблоком и апельсином.)
Если для идентификатора участника 1 автоматически выставляется счет за апельсин и банан, используется цена для повторного идентификатора группы 2.
Если для идентификатора участника 1 автоматически выставляется счет за яблоко, используется цена для повторяющегося идентификатора группы 3.
Если для идентификатора участника 1 автоматически выставляется счет за оранжевый, используется цена для повторяющегося идентификатора группы 4.
Если для идентификатора участника 1 автоматически выставляется счет за банан, используется цена для повторного идентификатора группы 5.

1 Ответ

0 голосов
/ 19 марта 2011

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

Запрашиваемый мною запрос был написан для 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)  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...