Mysql get top half of table then bottom half of table - mysql

I need to get the top half of my table in my first query and in the next query I need the bottom half.
I tried doing this for the top but it wont work
SELECT * FROM t_domains WHERE type_domain='radio' ORDER BY
date_created DESC LIMIT 0, (COUNT(*) / 2)
I need it as two queries for my function to work.
Anybody have any pointers or tips?

I would suggest doing 2 query's:
select count(*) from t_domains
to get the total count, and then get the data you want by using limit and offset:
select * from t_domains limit count/2
for the top and
select * from t_domains offset count/2
for the lower half......
This approach gives you also a way to limit the query's in another situation: what if the table contains 1 million records?

for first half
mysql-> SET #n := 0
mysql-> SELECT *,nnn FROM (
SELECT *, #n := #n + 1 AS nnn FROM t_domains ORDER BY date_created
) AS t
WHERE nnn <= ( SELECT COUNT(date_created) / 2 FROM t_domains ) AND type_domain = 'radio'
for second half, change here WHERE nnn <= this "<" on this ">"

As explained in MySQL's official documentation, LIMIT's two arguments must both be CONSTANTS except for prepared statements and stored programs. It does not seem very easy to simply store the count and later use it in a LIMIT clause.
As of version 8.0, MySQL has provided a ROW_NUMBER() function, which provides a much simpler solution than other answers have pointed out.
set #count=(select count(*)/2 from t_domains);
select * from (
select *, ROW_NUMBER() over (order by date_created desc) as row_num
from t_domains
) as t
where row_num <= #count
;
You may also check RANK(), which considers rows with equal values to have the same "ranking".

This always works.
Store the count
SELECT COUNT(*) FROM t_domains WHERE type_domain='radio'
Then use the stored count.
SELECT * FROM t_domains WHERE type_domain='radio' ORDER BY
date_created DESC LIMIT 0, {$stored_count/2}

Related

SELECT Where ID in (List of IDs) and limit records of each IDs in MySQL

I have met a situation that I have a list of IDs of a Store table and need to fetch the latest 10 files from each store.
SELECT *
FROM tblFiles
WHERE storeId in (IDs)
ORDER BY createdDate DESC
LIMIT 10
But, this limits the whole results. I found an answer to a similar SO question. But, the answer recommends using loop for each ID. This results in multiple DB hit.
Another option is to fetch all records and group them in the code. But, this will be heavy if there are large no.of records.
It'll be nice if it can be handled at the query level. Any help will be appreciated.
NB: The tables used here are dummy ones.
Pre-MySQL 8.0, the simplest method is probably variables:
select f.*
from (select f.*,
(#rn := if(#s = storeId, #rn + 1,
if(#s := storeId, 1, 1)
)
) as rn
from (select f.*
from tblfiles f
where storeId in (IDs)
order by storeId, createdDate desc
) f cross join
(select #s := 0, #rn := 0) params
) f
where rn <= 10;
In MySQL 8+ or MariaDB 10.3+, you would simply use window functions:
select f.*
from (select f.*,
row_number() over (partition by storeid order by createdDate desc) as seqnum
from tblfiles f
) f
where seqnum <= 10;
In older versions of MySQL and MariaDB, the innermost subquery may not be needed.
use select in where
SELECT * from tblFiles where storeId in (SELECT id from store ORDER BY datefield/id field desc limit 10)
You could workaround it with an UNIONed query, where each subquery searches for a particular id and enforces a LIMIT clause, like :
(SELECT *
FROM tblFiles
WHERE storeId = ?
ORDER BY createdDate DESC
LIMIT 10)
UNION
(SELECT *
FROM tblFiles
WHERE storeId = ?
ORDER BY createdDate DESC
LIMIT 10)
...
With this solution only one db hit will happen, and you are guarantee to get the LIMIT on a per id basis. Such a SQL can easily be generated from within php code.
Nb : the maximum allowed of UNIONs in a mysql query is 61.

Query to Display records except Initial Record

For my project, i have a requirement where i have to display all the records in descending order except the first record. I am kind of messed up. Anyways, i have tried the following:
SELECT * FROM ins_nr nl WHERE nl.nl_status = '2' ORDER BY nl.nl_id DESC
Here, i have a table called ins_nr which will display all the records with status 2 and the id which is the primary key(unique). It is displaying in desc order perfectly.
I dont want the first record from the top alone. What should i do? How to modify the above query..?
Use OFFSET. Then you can skip 1 records and select the remaining ones until the end.
Example:
SELECT * FROM ins_nr nl WHERE nl.nl_status = '2'
ORDER BY nl.nl_id DESC LIMIT 99999999999 OFFSET 1;
OR ( You could also use a shorter syntax to achieve the same result: )
$sql = "SELECT * FROM table_name LIMIT 1, 999999999";
You can generate dynamic rownum and filter on it to omit the first row, e.g.:
SELECT *
FROM (
SELECT nl.*, #r := #r + 1 AS `rn`
FROM ins_nr nl, (SELECT #r := 0)
WHERE nl.nl_status = '2'
ORDER BY nl.nl_id DESC
) a
WHERE a.rn > 1;
Another way is to get the max id from subquery and put it in a where clausole
You are looking for the offset clause. This looks like:
SELECT *
FROM ins_nr nl
WHERE nl.nl_status = '2'
ORDER BY nl.nl_id DESC
LIMIT 999999999 OFFET 1;
Unfortunately, LIMIT is required. For this situation, it is traditional to just put in a very large number.
Also, if nl_status is numeric, then use nl.nl_status = 2. Don't compare strings to numbers.

SQL limit result to top 50%

I tried two methods but failed in mysql.
/*see top 50% students, but this sql can't work*/
select * from student_table order by chinese_score desc limit count(*) * 0.5 ;
/*also can't work*/
set #num= floor((select count(*) from test.student_score)*0.5);
select * from student_table order by chinese_score desc limit #num ;
How to solve in mysql?
In Mysql this can be done in a single query using user defined variables.
You can store a value in a user-defined variable in one statement and
refer to it later in another statement. This enables you to pass
values from one statement to another.
SELECT * FROM (
SELECT student_table.*, #counter := #counter +1 AS counter
FROM (SELECT #counter:=0) AS initvar, student_table
ORDER BY student_table.chinese_score DESC
) AS result
WHERE counter < (#counter/2) ORDER BY chinese_score DESC;

Select limit percent

I want
example 10% of records in table
not 10 records
This query run in SQL Server
select top 10 percent * from tablename
Why this query in MySQL do not run?
select top 10 percent * from tablename
You could do it with a subquery, this is pretty basic since you want everything in one table:
SELECT *
FROM (
SELECT tablename.*, #counter := #counter +1 AS counter
FROM (select #counter:=0) AS initvar, tablename
ORDER BY value DESC
) AS X
where counter <= (10/100 * #counter);
ORDER BY value DESC
For MySQL use order by or limit
select * from tablename order by percent desc limit 10
TOP clause works on MSSQL server not sql.

Getting latest rows in MySQL based on date (grouped by another column)

This type of question is asked every now and then. The queries provided works, but it affects performance.
I have tried the JOIN method:
SELECT *
FROM nbk_tabl
INNER JOIN (
SELECT ITEM_NO, MAX(REF_DATE) as LDATE
FROM nbk_tabl
GROUP BY ITEM_NO) nbk2
ON nbk_tabl.REF_DATE = nbk2.LDATE
AND nbk_tabl.ITEM_NO = nbk2.ITEM_NO
And the tuple one (way slower):
SELECT *
FROM nbk_tabl
WHERE REF_DATE IN (
SELECT MAX(REF_DATE)
FROM nbk_tabl
GROUP BY ITEM_NO
)
Is there any other performance friendly way of doing this?
EDIT: To be clear, I'm applying this to a table with thousands of rows.
Yes, there is a faster way.
select *
from nbk_table
order by ref_date desc
limit <n>
Where is the number of rows that you want to return.
Hold on. I see you are trying to do this for a particular item. You might try this:
select *
from nbk_table n
where ref_date = (select max(ref_date) from nbk_table n2 where n.item_no = n2.item_no)
It might optimize better than the "in" version.
Also in MySQL you can use user variables (Suppose nbk_tabl.Item_no<>0):
select *
from (
select nbk_tabl.*,
#i := if(#ITEM_NO = ITEM_NO, #i + 1, 1) as row_num,
#ITEM_NO := ITEM_NO as t_itemNo
from nbk_tabl,(select #i := 0, #ITEM_NO := 0) t
order by Item_no, REF_DATE DESC
) as x where x.row_num = 1;