2012-01-06 3 views
0

у меня есть следующие три таблицы, которые я пытаюсь выполнить запрос:MySQL GROUP BY и ограничение присоединяется

заказов

id 

created_at 

ваучеры

id 

order_id 

initial_value 

current_value 

vouchers_used_in_orders

voucher_id 

order_id 

amount_used 

value_before 

value_after 

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

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

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

Это то, что я до сих пор:

SELECT 
YEAR(o.created_at) AS year_purchased, 
MONTH(o.created_at) AS month_purchased, 
SUM(IF(v.current_value = v.initial_value, 1, 1)) AS number_sold, 
SUM(IF(v.current_value = v.initial_value, 0, 1)) AS number_used, 
SUM(IF(v.current_value = v.initial_value, 1, 0)) AS number_not_used, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at) AND MONTH(vuo.created_at) = (MONTH(o.created_at)), 1, 0)) AS number_used_month_0, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 1 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 1 MONTH)), 1, 0)) AS number_used_month_1, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 2 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 2 MONTH)), 1, 0)) AS number_used_month_2, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 3 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 3 MONTH)), 1, 0)) AS number_used_month_3, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 4 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 4 MONTH)), 1, 0)) AS number_used_month_4, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 5 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 5 MONTH)), 1, 0)) AS number_used_month_5, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 6 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 6 MONTH)), 1, 0)) AS number_used_month_6, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 7 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 7 MONTH)), 1, 0)) AS number_used_month_7, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 8 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 8 MONTH)), 1, 0)) AS number_used_month_8, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 9 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 9 MONTH)), 1, 0)) AS number_used_month_9, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 10 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 10 MONTH)), 1, 0)) AS number_used_month_10, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 11 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 11 MONTH)), 1, 0)) AS number_used_month_11, 
SUM(IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 12 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 12 MONTH)), 1, 0)) AS number_used_month_12 
FROM vouchers v 
INNER JOIN orders o 
ON o.id = v.order_id 
LEFT OUTER JOIN vouchers_used_in_orders vu 
ON vu.voucher_id = v.id 
LEFT OUTER JOIN orders vuo 
ON vuo.id = vu.id 
GROUP BY 
YEAR(o.created_at), MONTH(o.created_at) 
ORDER BY 
YEAR(o.created_at), MONTH(o.created_at) 

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

Может ли кто-нибудь помочь?

Любые советы, оцененные.

Спасибо.

ответ

1

Не могли бы вы использовать COUNT DISTINCT на идентификаторе ваучера? (Вам нужно будет установить ложное условие в, если заявление будет нулевым, поэтому они не противопоказаны)

SELECT 
YEAR(o.created_at) AS year_purchased, 
MONTH(o.created_at) AS month_purchased, 
SUM(IF(v.current_value = v.initial_value, 1, 1)) AS number_sold, 
SUM(IF(v.current_value = v.initial_value, 0, 1)) AS number_used, 
SUM(IF(v.current_value = v.initial_value, 1, 0)) AS number_not_used, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at) AND MONTH(vuo.created_at) = (MONTH(o.created_at)), vuo.voucher_id, null)) AS number_used_month_0, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 1 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 1 MONTH)), vuo.voucher_id, null)))) AS number_used_month_1, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 2 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 2 MONTH)), vuo.voucher_id, null)))) AS number_used_month_2, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 3 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 3 MONTH)), vuo.voucher_id, null)))) AS number_used_month_3, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 4 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 4 MONTH)), vuo.voucher_id, null)))) AS number_used_month_4, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 5 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 5 MONTH)), vuo.voucher_id, null)))) AS number_used_month_5, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 6 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 6 MONTH)), vuo.voucher_id, null)))) AS number_used_month_6, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 7 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 7 MONTH)), vuo.voucher_id, null)))) AS number_used_month_7, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 8 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 8 MONTH)), vuo.voucher_id, null)))) AS number_used_month_8, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 9 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 9 MONTH)), vuo.voucher_id, null)))) AS number_used_month_9, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 10 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 10 MONTH)), vuo.voucher_id, null)))) AS number_used_month_10, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 11 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 11 MONTH)), vuo.voucher_id, null)))) AS number_used_month_11, 
COUNT(DISTINCT IF(YEAR(vuo.created_at) = YEAR(o.created_at + INTERVAL 12 MONTH) AND MONTH(vuo.created_at) = (MONTH(o.created_at + INTERVAL 12 MONTH)), vuo.voucher_id, null)))) AS number_used_month_12 
FROM vouchers v 
INNER JOIN orders o 
ON o.id = v.order_id 
LEFT OUTER JOIN vouchers_used_in_orders vu 
ON vu.voucher_id = v.id 
LEFT OUTER JOIN orders vuo 
ON vuo.id = vu.id 
GROUP BY 
YEAR(o.created_at), MONTH(o.created_at) 
ORDER BY 
YEAR(o.created_at), MONTH(o.created_at) 
0

Я бы объединить «ваучеры» и «заказы» в:

voucher_orders: 
    ID 
    purchase_date 
    value 

Тогда есть 'voucher_use':

 VoucherID 
    Amount 
    use_date 

Чтобы получить статистику:

select voucher_order.ID as v0, voucher_order.purchase_date, v2.ud left join 
( select min(use_date) ud from voucher_use as v1 where v1.VoucherID = v0.VoucherID limit 1) as v2 on v0.VoucherID = v2.VoucherID group by v0.purchase_date order by v0.purchase_date; 

Сделайте все, что вам нужно, останется в коде. Эту информацию не нужно хранить.

1

Это должно дать вам почти все, что вы ищете. В дополнение к подсчетам в месяц я также добавил общую сумму, использованную за эти месяцы. Сначала я начал запрос, чтобы получить ваучер, его первоначальную дату и что плюс 12 месяцев на вашу проблему. Я предварительно вычисляю месяцы один раз на каждый соответствующий «за ваучер», поэтому он может помочь упростить ваши конструкции SUM (IF()) для агрегаций. Для определения единственного количества ваучеров в моем предварительном заказе (V1), я сохранил первоначальный заказ, связанный с покупкой ваучера.Поэтому, используя это, я могу сделать SUM (IF()) того же идентификатора заказа. Если его одно, оно подсчитывается в VouchersUsed. При левом соединении с таблицей, используемой ваучером, если она возвращается как нуль, то нет экземпляров ее использования и будет значением NULL.

Вы также заметите, что я также принял меры предосторожности, чтобы предотвратить включение первоначального заказа через LEFT JOIN, явно запретив идентификатор заказа, используемый для того, чтобы ПОКУПАТЬ ваучер от подсчета и ложного выброса счета.

LEFT JOIN Vouchers_Used_In_Orders VUIO 
    ON V1.ID = VUIO.Voucher_ID 
    AND NOT V1.OriginalOrderID = VUIO.Order_ID 

Единственный элемент, я не могу проверить, и не имея MySQL в настоящее время является

СУММ (ЕСЛИ (VUIO.Voucher_ID = нулю, 1, 0)), как VouchersNotUsed,

Я думаю, что это пойдет, но может потребоваться изменить его на SUM (IF (VUIO.Voucher_ID равно null, 1, 0)). Надеюсь, что это помогает вам.

SELECT 
     YEAR(v1.VoucherStarted) as VoucherYear, 
     MONTH(v1.VoucherStarted) as VoucherMonth, 
     COUNT(distinct(v1.ID)) as UniqueVouchers, 
     SUM(IF(v1.OriginalOrderID = O.ID, 1, 0)) as VouchersUsed, 
     SUM(IF(VUIO.Voucher_ID = null, 1, 0)) as VouchersNotUsed, 
     SUM(IF(v1.OriginalOrderID = O.ID, 0, 1)) as TimesVouchersUsed, 

     SUM(IF(O.Created_At >= v1.VoucherStarted AND O.Created_At < v1.Plus1Month), 1, 0) as Month1Cnt, 
     SUM(IF(O.Created_At >= v1.VoucherStarted AND O.Created_At < v1.Plus1Month), VUIO.Amount_Used , 0) as Month1Amt, 

     SUM(IF(O.Created_At >= v1.Plus1Month AND O.Created_At < v1.Plus2Month), 1, 0) as Month2Cnt, 
     SUM(IF(O.Created_At >= v1.Plus1Month AND O.Created_At < v1.Plus2Month), VUIO.Amount_Used , 0) as Month2Amt, 

     SUM(IF(O.Created_At >= v1.Plus2Month AND O.Created_At < v1.Plus3Month), 1, 0) as Month3Cnt, 
     SUM(IF(O.Created_At >= v1.Plus2Month AND O.Created_At < v1.Plus3Month), VUIO.Amount_Used , 0) as Month3Amt, 

     SUM(IF(O.Created_At >= v1.Plus3Month AND O.Created_At < v1.Plus4Month), 1, 0) as Month3Cnt, 
     SUM(IF(O.Created_At >= v1.Plus3Month AND O.Created_At < v1.Plus4Month), VUIO.Amount_Used , 0) as Month3Amt, 

     SUM(IF(O.Created_At >= v1.Plus4Month AND O.Created_At < v1.Plus5Month), 1, 0) as Month4Cnt, 
     SUM(IF(O.Created_At >= v1.Plus4Month AND O.Created_At < v1.Plus5Month), VUIO.Amount_Used , 0) as Month4Amt, 

     SUM(IF(O.Created_At >= v1.Plus5Month AND O.Created_At < v1.Plus6Month), 1, 0) as Month5Cnt, 
     SUM(IF(O.Created_At >= v1.Plus5Month AND O.Created_At < v1.Plus6Month), VUIO.Amount_Used , 0) as Month5Amt, 

     SUM(IF(O.Created_At >= v1.Plus6Month AND O.Created_At < v1.Plus7Month), 1, 0) as Month6Cnt, 
     SUM(IF(O.Created_At >= v1.Plus6Month AND O.Created_At < v1.Plus7Month), VUIO.Amount_Used , 0) as Month6Amt, 

     SUM(IF(O.Created_At >= v1.Plus7Month AND O.Created_At < v1.Plus8Month), 1, 0) as Month7Cnt, 
     SUM(IF(O.Created_At >= v1.Plus7Month AND O.Created_At < v1.Plus8Month), VUIO.Amount_Used , 0) as Month7Amt, 

     SUM(IF(O.Created_At >= v1.Plus8Month AND O.Created_At < v1.Plus9Month), 1, 0) as Month8Cnt, 
     SUM(IF(O.Created_At >= v1.Plus8Month AND O.Created_At < v1.Plus9Month), VUIO.Amount_Used , 0) as Month8Amt, 

     SUM(IF(O.Created_At >= v1.Plus9Month AND O.Created_At < v1.Plus10Month), 1, 0) as Month9Cnt, 
     SUM(IF(O.Created_At >= v1.Plus9Month AND O.Created_At < v1.Plus10Month), VUIO.Amount_Used , 0) as Month9Amt, 

     SUM(IF(O.Created_At >= v1.Plus10Month AND O.Created_At < v1.Plus11Month), 1, 0) as Month10Cnt, 
     SUM(IF(O.Created_At >= v1.Plus10Month AND O.Created_At < v1.Plus11Month), VUIO.Amount_Used , 0) as Month10Amt, 

     SUM(IF(O.Created_At >= v1.Plus11Month AND O.Created_At < v1.Plus12Month), 1, 0) as Month11Cnt, 
     SUM(IF(O.Created_At >= v1.Plus11Month AND O.Created_At < v1.Plus12Month), VUIO.Amount_Used , 0) as Month11Amt, 

     SUM(IF(O.Created_At >= v1.Plus12Month), 1, 0) as Month12Cnt, 
     SUM(IF(O.Created_At >= v1.Plus12Month), VUIO.Amount_Used , 0) as Month12Amt 

    from 
     (SELECT 
       v.id, 
       v.initial_value, 
       v.order_id as OriginalOrderID 
       vo.created_at as VoucherStarted, 
       date_add(vo.created_at, INTERVAL 1 MONTH) as Plus1Month, 
       date_add(vo.created_at, INTERVAL 2 MONTH) as Plus2Month, 
       date_add(vo.created_at, INTERVAL 3 MONTH) as Plus3Month, 
       date_add(vo.created_at, INTERVAL 4 MONTH) as Plus4Month, 
       date_add(vo.created_at, INTERVAL 5 MONTH) as Plus5Month, 
       date_add(vo.created_at, INTERVAL 6 MONTH) as Plus6Month, 
       date_add(vo.created_at, INTERVAL 7 MONTH) as Plus7Month, 
       date_add(vo.created_at, INTERVAL 8 MONTH) as Plus8Month, 
       date_add(vo.created_at, INTERVAL 9 MONTH) as Plus9Month, 
       date_add(vo.created_at, INTERVAL 10 MONTH) as Plus10Month, 
       date_add(vo.created_at, INTERVAL 12 MONTH) as Plus11Month, 
       date_add(vo.created_at, INTERVAL 12 MONTH) as Plus12Month 
      from 
       vouchers v 
       join orders vo 
        ON v.order_id = vo.order_id) V1 

     LEFT JOIN Vouchers_Used_In_Orders VUIO 
     ON V1.ID = VUIO.Voucher_ID 
     AND NOT V1.OriginalOrderID = VUIO.Order_ID 

     LEFT JOIN Orders O 
      ON VUIO.Order_ID = O.ID 
      AND O.Created_At between V1.VoucherStarted and V1.Plus12Month 

    GROUP BY 
     YEAR(v1.VoucherStarted), 
     MONTH(v1.VoucherStarted)