Saturday, June 24, 2017

MySql - Get Min, Max, and 3 random Rows

Leave a Comment

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!

8 Answers

Answers 1

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 ) 

Answers 2

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  

Answers 3

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 

Answers 4

(select * from  table order by Price limit 1)   union  (select * from table  order by Price desc limit 4) 

Answers 5

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.

Answers 6

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  

Answers 7

This question may seem simple at first but there are a few possible gotchas:

Gotcha 1: All rows must be distinct. In particular, the 3 random rows shouldn't include the rows with the maximum or minimum price (since otherwise there could either be duplicate rows or less than 5 rows returned). UPDATE - Gotcha 1a: What if there are less than 5 rows in the table? Perhaps an edge case but presumably then all the rows should be returned exactly once.

Gotcha 2: Using ORDER BY in any of the subqueries could be very slow if there are a lot of rows.

The solution below attempts to get around these gotchas by picking single rows by ID and excluding the IDs that have already been picked when selecting random rows. (The random picking SQL is non-trivial but the complexity is necessary to overcome "Gotcha 2".)

Demo

http://rextester.com/OGLS84660

SQL

SELECT * FROM tbl WHERE ID IN ((SELECT @id1 := ID FROM tbl WHERE Price = (SELECT MIN(Price) FROM tbl) LIMIT 1),  (SELECT @id2 := ID FROM tbl WHERE ID <> @id1 AND Price = (SELECT MAX(Price) FROM tbl) LIMIT 1),  (SELECT @id3 := ID FROM (SELECT ID, (SELECT COUNT(*) AS cnt FROM tbl t2 WHERE t2.ID <= t1.ID AND t2.ID NOT IN (@id1, @id2)) AS cnt FROM tbl t1 WHERE t1.ID NOT IN (@id1, @id2)) t3 WHERE t3.cnt = (SELECT rnd FROM (SELECT ID, CEILING(RAND() * ((SELECT MAX(ID) FROM tbl) - (SELECT MIN(ID) FROM tbl) - 1)) AS rnd FROM tbl LIMIT 1) t4)),  (SELECT @id4 := ID FROM (SELECT ID, (SELECT COUNT(*) AS cnt FROM tbl t2 WHERE t2.ID <= t1.ID AND t2.ID NOT IN (@id1, @id2, @id3)) AS cnt FROM tbl t1 WHERE t1.ID NOT IN (@id1, @id2, @id3)) t3 WHERE t3.cnt = (SELECT rnd FROM (SELECT ID, CEILING(RAND() * ((SELECT MAX(ID) FROM tbl) - (SELECT MIN(ID) FROM tbl) - 2)) AS rnd FROM tbl LIMIT 1) t4)),  (SELECT ID FROM (SELECT ID, (SELECT COUNT(*) AS cnt FROM tbl t2 WHERE t2.ID <= t1.ID AND t2.ID NOT IN (@id1, @id2, @id3, @id4)) AS cnt FROM tbl t1 WHERE t1.ID NOT IN (@id1, @id2, @id3, @id4)) t3 WHERE t3.cnt = (SELECT rnd FROM (SELECT ID, CEILING(RAND() * ((SELECT MAX(ID) FROM tbl) - (SELECT MIN(ID) FROM tbl) - 3)) AS rnd FROM tbl LIMIT 1) t4))); 

Answers 8

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 )  
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment