MySQL get 2% of the record - mysql

I am trying to get 2% of the random sample record.
SELECT * FROM Orders
ORDER BY RAND()
LIMIT (SELECT CEIL(0.02 * (SELECT COUNT(*) FROM Orders)));
This one gives a syntax error due to line 3. Is there anything I am doing wrong?
Or is there a better way to get n % of records?

If you are using MySQL 8+, then ROW_NUMBER() provides one option:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY RAND()) rn,
COUNT(*) OVER () cnt
FROM Orders
)
SELECT *
FROM cte
WHERE 1.0*rn / cnt <= 0.02;
On MySQL 5.7 and earlier, we can simulate row number:
SELECT *
FROM
(
SELECT *, (#rn := #rn + 1) AS rn
FROM Orders, (SELECT #rn := 0) AS x
ORDER BY RAND()
) t
CROSS JOIN (SELECT COUNT(*) AS cnt FROM Orders) o
WHERE 1.0*rn / cnt <= 0.02;

Related

Randomly select half of records

I'm trying to generate a random sample of half of a table (or some other percentage). The table is small enough that I can use the ORDER BY RAND() LIMIT x approach. I'd like the code to sample 50% of recipients as the table changes size over time. Below was my first attempt but you can't put a subquery in a LIMIT clause. Any ideas?
SELECT
recipient_id
FROM
recipient
ORDER BY RAND()
LIMIT (
/* Find out how many recipients are on half the list */
SELECT
COUNT(*) / 2
FROM
recipient
);
If you are running MysQL 8.0, you can use window functions:
select *
from (select t.*, ntile(2) over(order by random()) nt from mytable t) t
where nt = 1
In earlier versions, one approach uses user variables:
select t.*
from (
select t.*, #rn := #rn + 1 rn
from (select * from mytable order by random()) t
cross join (select #rn := 0) x
) t
inner join (select count(*) cnt from mytable) c on t.rn <= c.cnt / 2

Trying to put a variable into limit to find a median

I trying to use mysql to solve the following solutions:
https://www.hackerrank.com/challenges/weather-observation-station-20/problem
Understanding that a variable cannot be put into LIMIT statement (from this )
My approach>
to declare a new variable to record rowIDs, and use rowID to retrieve the record in the middle.
However, it seems that rowID is not working well.
Could anyone give me some advises?
SELECT ROUND(COUNT(LAT_N)/2,0) FROM STATION into #count;
SELECT ROUND(a.LAT_N,4) FROM (
SELECT *,#row := #row + 1 FROM STATION s, (SELECT #row := 0) r
WHERE #row <=#count
ORDER BY s.LAT_N ASC) a
ORDER BY a.LAT_N DESC LIMIT 1;`
If you are running MySQL 8.0, this is simpler done with window functions:
select round(avg(lat_n), 4) median_lat_n
from (
select s.*, row_number() over(orer by lat_n) rn
from station s
where lat_n is not null
) s
where rn * 2 in (rn - 1, rn, rn + 1)
In earlier versions, variables make it bit tricky; we need one more level of nesting to make it safe:
select round(avg(lat_n), 2) median_lat_n
from (
select s.*, #rn := #rn + 1 rn
from (select * from station order by lat_n) s
cross join (select #rn := 0) p
) s
where rn * 2 in (rn - 1, rn, rn + 1)
The logic is as follows: first enumerate the rows, ordered by lat_n. If the row count is uneven, we pick the middle row; if it is even, we take the average of the two middle values.

MYSQL subquery in a LIMIT

I was wondering if it's possible to use a subquery inside a LIMIT.
The reason why I'd like to use this, is to return 20% (1/5th) of the best buying customers.
For instance (though this clearly doesn't work):
SELECT id, revenue
FROM customers
ORDER BY revenue DESC
LIMIT (SELECT (COUNT(*) / 5) FROM customer)
Is there a way to make a subquery in a limit, or return 20% in a different way?
A typical way of doing this using ANSI SQL is with window functions:
SELECT id, revenue
FROM (SELECT c.*,
ROW_NUMBER() OVER (ORDER BY revenue DESC) as seqnum,
COUNT(*) OVER () as cnt
FROM customers
) c
WHERE seqnum <= cnt * 0.2
ORDER BY revenue DESC;
Most databases support these functions.
MySQL is one of the few databases that do not support window functions. You can use variables:
SELECT id, revenue
FROM (SELECT c.*, (#rn := #rn + 1) as rn
FROM customers c CROSS JOIN
(SELECT #rn := 0) params
ORDER BY c.revenue DESC
) c
WHERE rn <= #rn / 5; -- The subquery runs first so #rn should have the total count here.

MySQL Over Convert from SQL to MySQL

Can anyone help me covert this SQL statement into MySQL.
Its being used for jQuery datatables for server side pagination.
I have tried using
#curRank := #curRank + 1 AS rank
instead of
row_number() OVER (ORDER BY item_id asc) AS RowNumber
but i keep getting a syntax error
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS (SELECT * INTO temp1 FROM item where BLOCKED='0');
SELECT *
FROM
(SELECT row_number() OVER (ORDER BY item_id asc) AS RowNumber , *
FROM
(SELECT (SELECT count(temp1.NO)
FROM
temp1) AS TotalRows
, ( SELECT count(NO) FROM temp1 ) AS TotalDisplayRows ,*
FROM
temp1 ) RawResults) Results
WHERE
RowNumber BETWEEN 1 AND 10
Thanks for your help, Here is the query. But how can i return TotalRows and TotalDisplayRows into the data ? i had to manually add the item_id and description. The colums i get outputted are RowNumber, Item_Id, Description. I also need TotalRows amd TotalDisplayRows
set #rn := 0;
SELECT *
FROM (SELECT (#rn := #rn + 1) AS RowNumber,item_id,description
FROM
(SELECT (SELECT count(item.item_id)
FROM
item) AS TotalRows
, ( SELECT count(item_id) FROM item ) AS TotalDisplayRows ,item_id,description
FROM
item ) RawResults
) Results
WHERE
RowNumber BETWEEN 1 AND 10
You can use variables:
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS (SELECT * INTO temp1 FROM item where BLOCKED='0');
SELECT *
FROM (SELECT (#rn := #rn + 1) AS RowNumber , *
FROM (SELECT (SELECT count(temp1.NO)
FROM temp1
) AS TotalRows,
(SELECT count(NO) FROM temp1 ) AS TotalDisplayRows ,*
FROM temp1
) RawResults CROSS JOIN
(SELECT #rn := 0) vars
ORDER BY item_id
) Results
WHERE RowNumber BETWEEN 1 AND 10
If you don't actually need the RowNumber column in the table, you could just use limit and offset.
SELECT * FROM (SELECT (#rn := #rn + 1) AS RowNumber,item_id,description
FROM
(SELECT (SELECT count(item.item_id)
FROM
item) AS TotalRows
, ( SELECT count(item_id) FROM item ) AS TotalDisplayRows ,item_id,description
FROM
item ) RawResults
) Results
WHERE RowNumber BETWEEN 1 AND 10

Translate MySQL to Postgres

I am looking for help converting my MySQL query to work in PostgreSQL. This is a query on the model of RoR application.
Any help is appreciated.
SELECT * FROM(
SELECT #row := #row + 1 AS rownum, id, device_id, name, quarterly
FROM (SELECT #row :=0) r, recurrent_tests
WHERE device_id = "+self.id.to_s+" AND quarterly = 1
ORDER BY name ASC
) ranked
WHERE (rownum-1) % 4 = "+(i-1).to_s)
select *
from (
select row_number() over (order by name asc) as rownum,
id,
device_id,
name,
quarterly
from recurrent_tests
) t
where rownum - 1 % 4 = ...
For more details on window functions (the over (...) clause) please see the manual:
http://www.postgresql.org/docs/current/static/tutorial-window.html