Home > other >  How to achieve 'buy X items get Y items free function'
How to achieve 'buy X items get Y items free function'

Time:10-14

Here I have a table called Products:

id transaction_id type price rank
1 1 a 350 1
2 1 a 250 2
3 1 a 150 3
4 1 a 100 4
5 1 a 100 5
6 1 a 50 6
7 2 b 400 1
8 2 b 100 2
9 2 b 60 3

Requirements: Whenever you buy three 'a' items, the cheapest of the three will be free; Whenever you buy two 'b' items, the cheapest of the two will be free. The results table should be like:

transaction_id price
1 800
2 460

Explanation: For transaction_id 1, the total cost is: 350 250 100 100=800 (the items whose id == 3 and 6 have become free; For transaction_id 2, the total cost is: 400 60=460 (the item whose id == 8 has become free)

I have no clue about how to select all the free items.

CodePudding user response:

For MySQL 8.0 , you can use the ROW_NUMBER() window function as the following:

select transaction_id, sum(discount_price) as price
from
  (
    select transaction_id, 
       case 
           when (type='a' and row_number() over (partition by transaction_id, type order by price desc) % 3=0) 
             or (type='b' and row_number() over (partition by transaction_id, type order by price desc) % 2=0) 
           then 0
           else price 
       end as discount_price
    from table_name
  ) T
group by transaction_id
order by transaction_id

See a demo.

For older versions of MySQL, you can simulate the ROW_NUMBER() functionality as the following:

set @tid=null;
set @tp=null;
set @rn=0;
select D.transaction_id, sum(D.discount_price) as price
from
   (
     select T.transaction_id, 
       case 
           when (T.type='a' and T.rn % 3=0) 
             or (T.type='b' and T.rn % 2=0) 
           then 0
           else T.price 
       end as discount_price
     from
        (
          select *, 
            if(@tid<> transaction_id or @tp <> type,@rn:=1,@rn:=@rn 1) rn, 
            @tid:=transaction_id, @tp:= type
          from table_name
          order by transaction_id,type, price desc
        ) T
  ) D
group by D.transaction_id
order by D.transaction_id

See a demo.

CodePudding user response:

According to your comments on my previous answer, you want to be able to exclude the cheapest N products from an X number of bought products for a specific type. i.e. Whenever you buy four 'a' items, the cheapest two of the four will be free.

consider the following query:

set @package_size_a=4; /* number of items should be bought from type 'a' to get the offer */
set @package_size_b=2; /* number of items should be bought from type 'b' to get the offer */
set @remove_from_a_cheapest=2; /* number of cheapest products to be excluded from type 'a' */
set @remove_from_b_cheapest=1; /* number of cheapest products to be excluded from type 'b' */
set @tid=null; /* reset row number to 1 whenever this value <> current transaction_id according to the selection order */
set @tp=null; /* reset row number to 1 whenever this value <> current type according to the selection order */
set @rn=0; /* row number set by the if statement inside the query */

select D.transaction_id, sum(D.discount_price) as price
from
   (
     select T.transaction_id, 
            case 
             when (T.type='a' and T.rn > @remove_from_a_cheapest) 
             or (T.type='b' and T.rn > @remove_from_b_cheapest) 
             then 0
             else T.price 
            end as discount_price
    from
        (
          select *, 
                 if(@tid<> transaction_id or 
                    @tp <> type or 
                    (type='a' and @rn=@package_size_a) or /* the row number exceeds the package_size_a value, then reset to 1 */
                    (type='b' and @rn=@package_size_b), /* the row number exceeds the package_size_b value, then reset to 1 */
                    @rn:=1, @rn:=@rn 1) rn, 
            @tid:=transaction_id, @tp:= type
          from table_name
          order by transaction_id, type, price desc
        ) T
   ) D
group by D.transaction_id
order by D.transaction_id  

The comments in the query explain how this query works.

If you have other types than (a and b), you can modify the query to include them.

Last thing, it's highly recommended to think about upgrading your MySQL version.

See a demo.

  • Related