10

I want a MySql query to get 5 rows which include min price row, max price row and other 3 random row.

Table:

ID  Product Price
1   data    2
2   data    20
3   data    55
4   data    24
5   data    2
6   data    15
7   data    10
8   data    33
9   data    3
10  data    30

Expected Result(with 3 random rows)

ID  Product Price
1   data    2
3   data    55
4   data    24
6   data    15
7   data    10

Any help would be greatly appreciated!

keerthi
  • 769
  • 2
  • 9
  • 24
  • random select refer to[MySQL select 10 random rows from 600K rows fast](https://stackoverflow.com/q/4329396/6521116) ; max select refer to[SQL Select only rows with Max Value on a Column](https://stackoverflow.com/q/7745609/6521116); min select refer to[MYSQL how to select data where a field has a min value](https://stackoverflow.com/q/13357144/6521116) – LF00 Jun 17 '17 at 11:31

7 Answers7

10
SELECT table.*
  FROM table
     , ( SELECT @minPrice := ( SELECT min(Price) FROM table ) minPrice
              , @minId    := ( SELECT id FROM table WHERE Price = @minPrice ORDER BY rand() LIMIT 1 )
              , @maxPrice := ( SELECT max(Price) FROM table ) maxPrice
              , @maxId    := ( SELECT id FROM table WHERE Price = @maxPrice ORDER BY rand() LIMIT 1 )
       ) tmp
  WHERE table.id in (@minId,@maxId)
UNION
(SELECT *
   FROM table
   WHERE Price not in (@minPrice,@maxPrice)
   ORDER BY rand()
   LIMIT 3
)
Sal
  • 1,307
  • 1
  • 8
  • 16
  • Hi, I have one more condition to be included, that is, The table have one more column product ID, I need to take 5 products(min max and 3 random) from each product ID. Could you please help? – keerthi Jun 19 '17 at 04:12
  • Query would be different depending on desired output. However, as @Strawberry suggested, you can LOOP by product ID and simply filter by product ID in all WHERE clauses where table (prices) is used. – Sal Jun 19 '17 at 16:21
6

You can do this like ,

select * from table order by Price asc limit 0,1
union all
select * from table order by Price desc limit 0,1 
union all
select * from table order by RAND()  limit 0,3 
LF00
  • 27,015
  • 29
  • 156
  • 295
Vibha Chosla
  • 733
  • 5
  • 12
2

you can get it with UNION and sub-query:

(SELECT * FROM table ORDER BY Price ASC LIMIT 0 , 1 )
UNION ALL 
(SELECT * FROM table ORDER BY Price DESC limit 0,1 )
UNION ALL 
(SELECT * FROM table WHERE Price NOT IN ( SELECT CONCAT( MIN(  `Price` ) ,  ',', MAX(  `Price` ) ) AS MaxPrice FROM table ) ) ORDER BY RAND( ) LIMIT 0 , 3 ) 
Bhunesh Satpada
  • 770
  • 1
  • 6
  • 19
1

So ... get the min, get the max, get all the other records that are not min and max, sort by rand and return the first 3 that are not min and max.

Here is the SQL fiddle

-- get the first occurence of any item matching the products and prices returned
select min(top_bottom_and_3_random.id) id, top_bottom_and_3_random.product, top_bottom_and_3_random.price from (
    -- get the min and the max
    select distinct product, price from top_bottom_and_3_random where price in (
        select max( price) from top_bottom_and_3_random
        union select min( price ) from top_bottom_and_3_random
    ) union 
    select product, price from ( 
        -- get 3 random rows that are not max or min
        select rand() rand, product, price from (
            select product, price from top_bottom_and_3_random where price not in (
                select max( price) from top_bottom_and_3_random
                union select min( price ) from top_bottom_and_3_random
            ) group by product, price
        ) rand_product_price_group
         order by rand
         limit 3
    ) random_mix
) min_max_3_random
inner join top_bottom_and_3_random
on min_max_3_random.product = top_bottom_and_3_random.product
and min_max_3_random.price = top_bottom_and_3_random.price
group by top_bottom_and_3_random.product, top_bottom_and_3_random.price
order by id

-- example results
id  product price
1   data    2
3   data    55
4   data    24
7   data    10
10  data    30
Keith John Hutchison
  • 4,955
  • 11
  • 46
  • 64
1
SELECT x.*
  FROM my_table x 
  JOIN (SELECT MIN(price) a, MAX(price) b FROM my_table) y 
 ORDER 
    BY COALESCE(x.price NOT IN (a,b))
     , RAND() 
 LIMIT 5;

To address Keith's concerns... so, if we should always have 3, and either 1 or 5...

SELECT x.id
     , x.product
     , x.price
  FROM my_table x 
  JOIN (
        (SELECT id FROM my_table ORDER BY price, RAND() LIMIT 1)
        UNION
        (SELECT id FROM my_table ORDER BY price DESC, RAND() LIMIT 1)
       ) y
   GROUP
      BY x.id
       , x.product
       , x.price
 ORDER 
    BY MIN(COALESCE(x.id != y.id)) 
     , RAND()
 LIMIT 5;

...but this is starting to be a bit of a mouthful - it may be smarter to solve this in application code.

Strawberry
  • 33,750
  • 13
  • 40
  • 57
1

You can take help of MySQL sub-query to get the desired result

select * from table WHERE Price = (SELECT MIN(Price ) FROM table)
union all
select * from table WHERE Price = (SELECT MAX(Price ) FROM table)
union all
select * from table order by RAND()  limit 0,3 
RAUSHAN KUMAR
  • 5,846
  • 4
  • 34
  • 70
0
(select * from  table order by Price limit 1) 
 union 
(select * from table  order by Price desc limit 4)
Mattia Dinosaur
  • 891
  • 10
  • 29