Get random records in MySql - mysql

I have a sql table, Employee which has 4 columns.
Id
Name
Address
Status – Fixed Type (Enum). Having 3 fixed values – OPEN, CLOSED and PENDING.
Let’s assume Total Records in the table are 200.
Now, I want to form a query which would return -
50 random records which have status “OPEN”.
25 random records which have status “CLOSED”.
45 random records which have status “PENDING”.
I have tried with the one fragmented query and it worked fine but looking for single query solution for whole scenario.
Select * from Employee a where a.Status = 'OPEN' ORDER BY RAND() LIMIT 50
Select * from Employee a where a.Status = 'CLOSED' ORDER BY RAND() LIMIT 25
Select * from Employee a where a.Status = 'PENDING' ORDER BY RAND() LIMIT 45
Any help would be highly appreciated.

Do you need it as a single query (mildly painful) or as 3 separate queries?
As 3 separate queries, the simplest option would be something like
Select * from Employee where Status = 'OPEN' ORDER BY RAND() LIMIT 50;
Select * from Employee where Status = 'CLOSED' ORDER BY RAND() LIMIT 25;
Select * from Employee where Status = 'PENDING' ORDER BY RAND() LIMIT 45;

Use Union to combine multiple queries and remember to assign alias for each sub/parent query.
select * from ((Select * from Employee a where a.Status = 'OPEN' ORDER BY RAND() LIMIT 50)
union
(Select * from Employee b where b.Status = 'CLOSED' ORDER BY RAND() LIMIT 25)
union
(Select * from Employee c where c.Status = 'PENDING' ORDER BY RAND() LIMIT 45)) d;
I hope this will be useful for someone.

Related

Fetch only 2 results, one for each different value of a concrete field

In a MYSQL table with those 5 fields: id, user_id, date, type, uid where type can be 1 or 2, I'm looking for a single query where I can fetch 2 results, one for type=1 and another one for type=2 based on date field.
Right now i have the following query which only gives me the last uid without taking care of the type field.
SELECT t.uid
FROM table AS t
WHERE t.user_id = 666
ORDER BY t.date
DESC LIMIT 1
Does anyone know how should modify this query so i can get the last uid for type=1 and the last one for type=2 based on date field? I would like to keep a a single query
Union all is probably the simplest method:
(select t.*
from t
where t.user_id = 666 and t.type = 1
order by date desc
limit 1
) union all
(select t.*
from t
where t.user_id = 666 and t.type = 2
order by date desc
limit 1
)
Finally i updated the query following this "paradigm":
http://dev.mysql.com/doc/refman/5.7/en/example-maximum-column-group-row.html
http://jan.kneschke.de/projects/mysql/groupwise-max/
This is how the query ended up:
SELECT s1.type, s1.uid
FROM t AS s1
LEFT JOIN t AS s2 ON s1.type = s2.type AND s1.date < s2.date
WHERE s2.date IS NULL;
Here's a visual example: http://hastebin.com/ibinidasuw.vhdl
Credits are for snoyes from #sql on Freenode. :)

Why does my code in rand() not work in mysql?

My userid is guid,it is not int.At first,I user ORDER BY RAND() and it works.But someone say that it is not efficient.So I try to change it to other ways.But it can not work.How to fix it?
-- work fine but not efficient
select userid from user order by rand() LIMIT 1
-- do not work,always return the same row
SELECT * FROM user WHERE userid >= ((SELECT MAX(userid) FROM user)
-(SELECT MIN(userid) FROM user)) * RAND()
+ (SELECT MIN(userid) FROM _user) LIMIT 1
-- do not work,always return the same row
SELECT userid FROM user AS t1 JOIN (SELECT RAND()
* (SELECT MAX(userid) FROM user) AS id) AS t2
WHERE t1.userid >= t2.id
ORDER BY t1.userid ASC LIMIT 1;
You are treating a guid as an integer. That just isn't going to work. The problem is not rand(), it is mistreatment of types.
One method that can make the query more efficient is to do something like this:
select userid
from user
where rand() < 0.01
order by rand()
limit 1;
This takes about 1% of your table and uses that for sorting. You can actually formalize this to something like:
select userid
from user cross join (select count(*) as cnt from user) params
where rand() < 100 / cnt
order by rand()
limit 1;
This will select about 100 rows from the table and sort those. Sorting 100 rows is not particularly intensive, so that should be reasonable performance-wise. And, with an expected value of 100 rows, the query should basically never fail to get at least one row.

Improve MySQL Union Statement

I have the following mySql statement, which I am sure can be made more efficient, I'm just not sure what would be the best way... the only difference is the equip_id that changes in the WHERE clause...
==============
(SELECT
`receipt_ts`,
`driver_id`,
`equip_id`,
`pos_lon`,
`pos_lat`,
`pos_timestamp`
FROM `log_messaging`
WHERE `equip_id`='207' AND `tran_type`='T.2.12.0'
ORDER BY receipt_ts DESC LIMIT 1 )
UNION
(SELECT
`receipt_ts`,
`driver_id`,
`equip_id`,
`pos_lon`,
`pos_lat`,
`pos_timestamp`
FROM `log_messaging`
WHERE `equip_id`='212' AND `tran_type`='T.2.12.0'
ORDER BY receipt_ts DESC LIMIT 1 )
UNION
(SELECT
`receipt_ts`,
`driver_id`,
`equip_id`,
`pos_lon`,
`pos_lat`,
`pos_timestamp`
FROM `log_messaging`
WHERE `equip_id`='213' AND `tran_type`='T.2.12.0'
ORDER BY receipt_ts DESC LIMIT 1 );
================
I am unioning each returned row to build a dataset of max(receipt_ts) for multiple equip_id's. (I need to get the most recent positioning for the equipment.
Sometimes the query ends up being for 100+ unique equip_id's.
I am trying to make the query execute quicker than it currently is (about 7 seconds for ~100 UNIONS as above...
Point me in the right direction??
Thanks!
I would use the IN clause :
SELECT receipt_ts, driver_id, equip_id, pos_lon, pos_lat, pos_timestamp
FROM log_messaging a
JOIN (SELECT c.equip_id, max(c.receipt_ts) as receipt
FROM log_messaging c
WHERE equip_id in ('207', '212', '213')
AND tran_type='T.2.12.0'
GROUP by c.equip_id) b USING(equip_id)
WHERE b.receipt = a.receipt_ts
ORDER BY a.receipt_ts
Note that if you really want to use the UNION (I don't see why you would) but want to optimize it, you could use the UNION ALL which would be more performent as UNION check datas for duplicata removal which consume more process.
First, you should use union all rather than union. So start with this query:
(SELECT receipt_ts, driver_id, equip_id, pos_lon, pos_lat, pos_timestamp
FROM log_messaging
WHERE equip_id = '207' AND tran_type = 'T.2.12.0'
ORDER BY receipt_ts DESC
LIMIT 1
) UNION ALL
(SELECT receipt_ts, driver_id, equip_id, pos_lon, pos_lat, pos_timestamp
FROM log_messaging
WHERE equip_id = '212' AND tran_type = 'T.2.12.0'
ORDER BY receipt_ts DESC
LIMIT 1
) UNION ALL
(SELECT receipt_ts, driver_id, equip_id, pos_lon, pos_lat, pos_timestamp
FROM log_messaging
WHERE equip_id = '213' AND tran_type = 'T.2.12.0'
ORDER BY receipt_ts DESC
LIMIT 1
) ;
This is a reasonable query. I would suggest that you create an index on log_messaging(tran_type, equip_id, recipt_ts).

MySQL: Select records where COUNT

I'm trying to select 1000 customers that have placed exactly 1 order. Everything is in the Orders table.
select * from Order having count(CustomerID) = 1 limit 1000
So basically all records that have only one occurence of the CustomerID in the entire table. This returns an empty result set and there are 100,000s in the table.
You need to GROUP in order to (meaningfully) use the HAVING clause. The following works as expected:
SELECT
*
FROM
`Order`
GROUP BY
CustomerID
HAVING
COUNT(CustomerID) = 1
LIMIT 1000
UPDATE
Adding WHERE (see comments):
SELECT
*
FROM
`Order`
WHERE
Language = 'EN'
GROUP BY
CustomerID
HAVING
COUNT(CustomerID) = 1
LIMIT 1000
SELECT * FROM `Order`
GROUP BY CustomerID
HAVING COUNT(CustomerID) = 1
LIMIT 1000
try
select count(CustomerID) as counter ,o.* from Order o
group by CustomerID having counter = 1 limit 1000
Add group by to query for correct output, e.g:
select *
from Order
group by CustomerID
having count(CustomerID) = 1
limit 1000
SELECT CustomerID FROM Order GROUP BY CustomerID HAVING COUNT(*) = 1 LIMIT 1000

mysql query to select one specific row and another random row

I want to display two records.
For eg
select * FROM users WHERE user_id = 5.
Now i want another row randomly selected from users table but with user_id != 5
Is it possible to do in a single query. I tried using union all but i dnt get two distinct rows.
Thanks
This works fine for me. The first result is always the record with ID 5, the second row is a random one. Note that if no record with the ID 5 exists, both rows will be random.
SELECT * FROM users ORDER BY (user_id = 5) DESC, RAND() LIMIT 0,2
Try this
SELECT * FROM users WHERE user_id = 5 || user_id != 5 ORDER BY RAND() LIMIT 2
Union should do the trick. You probably forgot LIMIT.
(SELECT * FROM users WHERE user_id = 5 LIMIT 1)
UNION
(SELECT * FROM users WHERE user_id != 5 LIMIT 1)
Try this:
SELECT * FROM users WHERE user_id=5
union all (
SELECT * FROM users WHERE user_id!=5
ORDER BY RAND() LIMIT 0,1)