MySQL select rows until fixed number of condition is reached - mysql

I have this table
id fruit
---------
1 apple
2 banana <--
3 apple
4 apple
5 apple
6 apple
7 banana <----
8 apple
9 banana
10 apple
And I want to select rows until 2 bananas are found, like
SELECT id FROM table_fruit UNTIL number_of_bananas = 2
So the result would be 1,2,3,4,5,6,7
How could I achieve this?
thanks
I wish I could give credits to all of you who answered my question. I'v tested all of them, and they all work perfectly (got the expected result).
Though answers of Devart and ypercube seem a little bit complex and difficult for me to understand.
And since AnandPhadke was the first one provided a working solution, I'll choose his answer as accepted.
You guys are awesome, thanks!

Try this query -
SELECT id, fruit FROM (
SELECT
b.*, #b:=IF(b.fruit = 'banana', 1, 0) + #b AS banana_number
FROM
bananas b,
(SELECT #b := 0) t
ORDER BY id) t2
WHERE
banana_number < 2 OR banana_number = 2 AND fruit = 'banana'
SQLFiddle demo

select * from tables where id <=
(
select id from (
select id from tables where fruit='banana'
order by id limit 2) a order by id desc limit 1
)
SQLFIDDLE DEMO

#Devart's answer is perfect but it's an alternative option to we can use:
SELECT * FROM table_fruit WHERE id <=
(
SELECT id FROM
(SELECT id FROM table_fruit WHERE fruit='banana' ORDER BY id LIMIT 2) a
ORDER BY ID DESC LIMIT 1
);
Or using MAX
SELECT * FROM table_fruit WHERE id <=
(
SELECT MAX(id) FROM
(SELECT id FROM table_fruit WHERE fruit='banana' ORDER BY id LIMIT 2) a
);
See this SQLFiddle

select * from table_fruit where id <=
(
select max(id) from
(select id from table_fruit where fruit='banana' order by id limit 2) t
)

If there are less than 2 rows with 'banana', this will return all rows of the table:
SELECT t.*
FROM table_fruit AS t
JOIN
( SELECT MAX(id) AS id
FROM
( SELECT id
FROM table_fruit
WHERE fruit = 'banana'
ORDER BY id
LIMIT 1 OFFSET 1
) AS lim2
) AS lim
ON t.id <= lim.id
OR lim.id IS NULL ;

Related

How to get the MAX value in MySQL?

How to get the MAX value in every albumID(45, 12, 22, 8) in the following table?
I tried with this query.
But it returned me the first value, not max value.(3, 6, 5, 6)
SELECT
*
FROM
(
SELECT
*
FROM
contentnew
WHERE
genreID = 1
ORDER BY
albumID DESC,
reg_count DESC
) AS newTB
GROUP BY
albumID;
Look this
If I use the
Once you group by, you can apply aggregate functions such as max on each group. In your example try:
SELECT albumID, max(reg_count) as max_count
FROM contentnew
GROUP BY albumID
This will project each albumID with the max_count in the group. In the select statement you can only use aggregate functions. The reason why we are able to project (or print) albumID is because this is the column we grouped by.
Following comments:
SELECT *
FROM contentnew as c1
WHERE c1.reg_count < (
SELECT max(c2.reg_count)
FROM contentnew as c2
WHERE c1.albumID = c2.albumID
GROUP BY c2.albumID)
You can try
select max(reg_count) from contentnew group by albumID
You are almost there, one thing that might be helpful is to use row_number() function, if you want every column from the table.
with contentnew_test
as
(
select row_number() over (partition by albumId order by reg_count desc) row
,* from
contentnew
)
select * from contentnew_test where row = 1 order by reg_count desc;
I used this as a reference as not sure about the syntax
https://www.mysqltutorial.org/mysql-window-functions/mysql-row_number-function/
Subquery will give you a result set something like this:
row albumId reg_count ...
1 1 8 ...
2 1 7 ...
3 1 3 ...
4 1 1 ...
1 2 22 ...
2 2 9 ...
3 2 6 ...
4 2 1...and so on.

Select the last record in MySQL in WHERE condition

I have a table that store ticket and statue relation
ticketstatus_Id ticket_Id status_Id
===================================
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2 *
6 3 1
7 4 1
8 3 2 *
I want to select rows that last status_Id equal 2 ,Rows are marked in table.
I think I have to use GROUP BY on column ticket_Id but it return with first status_Id.
This problem is a good candidate for ROW_NUMBER:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY ticket_Id ORDER BY ticketstatus_Id DESC) rn
FROM yourTable
)
SELECT ticketstatus_Id, ticket_Id, status_Id
FROM cte
WHERE rn = 1 AND status_Id = 2;
The above logic finds all latest rows for each ticket_Id, as ordered by the ticketstatus_Id, whose status_Id values also happens to be 2.
All records with status_Id= '2'
Select * from TABLENAME where status_Id = '2'
Last record with status_Id= '2'
Select * from TABLENAME where status_Id = '2' order by ticketstatus_Id desc limit 1
SELECT * from TABLENAME where status_Id = '2' ORDER BY ticketstatus_Id DESC LIMIT 1;
You can do this with group by and a having clause:
select ticket_Id, max(ticketstatus_Id)
from ticketstatuses
group by ticket_id
having max(ticketstatus_Id) = max(case when status_id = 2 then ticketstatus_Id end);
It would be interesting to know if this has better performance than the row_number() version. However, for performance, this is probably best:
select ts.*
from ticketstatuses ts
where ts.ticketstatus_Id = (select max(ts2.ticketstatus_Id)
from ticketstatus ts2
where ts2.ticket_id = ts.ticket_id
) and
ts.status_id = 2;
This can take advantage of an index on (ticket_id, ticketstatus_id).

Mysql - Get the difference between two sequential values

I want to get the difference between two sequential values from my table.
| id | count |
| 1 | 1 |
| 2 | 7 |
| 3 | 9 |
| 4 | 3 |
| 5 | 7 |
| 6 | 9 |
For example the difference between
id2-id1 = 6,
id3-id2 = -2,
...
How can I do it? SELECT SUM(id(x+1) - id(x)) FROM table1
You can use a subquery to find count for the preceding id.
In case there are no gaps in the ID column:
SELECT CONCAT(t.`id` ,' - ', t.`id` - 1) AS `IDs`
, t.`count` - (SELECT `count`
FROM `tbl`
WHERE `id` = t.`id` - 1) AS `Difference`
FROM `tbl` t
WHERE t.`id` > 1
SQLFiddle
In case there are gaps in the IDcolumn.
First solution, using ORDER BY <...> DESC with LIMIT 1:
SELECT CONCAT(t.id ,' - ', (SELECT `id` FROM tbl WHERE t.id > id ORDER BY id DESC LIMIT 1)) AS IDs
, t.`count` - (SELECT `count`
FROM tbl
WHERE t.id > id
ORDER BY id DESC
LIMIT 1) AS difference
FROM tbl t
WHERE t.id > 1;
SQLFiddle
Second solution, using another subquery to find count with the MAX(id) less than current id:
SELECT CONCAT(t.id ,' - ', (SELECT MAX(`id`) FROM tbl WHERE id < t.id)) AS IDs
, t.`count` - (SELECT `count`
FROM tbl
WHERE `id` = (SELECT MAX(`id`)
FROM tbl
WHERE id < t.id)
) AS difference
FROM tbl t
WHERE t.id > 1;
SQLFiddle
P.S. : First column, IDs, is just for readability, you can omit it or change completely, if it is necessary.
If you know that the ids have no gaps, then just use a join:
select t.*, (tnext.count - t.count) as diff
from table t join
table tnext
on t.id = tnext.id - 1;
If you just want the sum of the differences, then that is the same as the last value minus the first value (all the intermediate values cancel out in the summation). You can do this with limit:
select last.count - first.count
from (select t.* from table order by id limit 1) as first cross join
(select t.* from table order by id desc limit 1) as last;
Try this:
SELECT MAX(count)-MIN(count) diff WHERE id IN(1,2)
Or this way
SELECT 2*STD(count) diff WHERE id IN(1,2)
This works even if ids have distances between them:
SELECT *,
((SELECT value FROM example e2 WHERE e2.id > e1.id ORDER BY id ASC LIMIT 1) - value) as diff
FROM example e1;

mysql - return rows in ascending order

I have a table containing 392871961 rows like this.
p_id r_p_id weight
1 2 0.223923923
1 3 0.12923923
1 4 0.423926924
1 5 0.143921921
1 6 0.323923922
1 7 0.223923728
.
.
.
2 1 0.123923921
2 3 0.023923922
2 4 0.223923926
2 5 0.323923928
2 6 0.223923921
2 7 0.423923921
.
.
.
3 1 0.023923925
3 2 0.223923922
3 4 0.123923926
3 5 0.223923929
3 6 0.123923921
3 7 0.523923922
.
.
.
p_id goes up to a little over 6000 digit. weight represents some kind of priority between p_id and r_p_id.
I have two queries like this. A user is going to provide list of p_ids. It would be less than 10 p_ids.
first query = select r_p_id, weight from table where p_id in (....) order by weight
second query = select r_p_id, (weight*0.8) as m_weight from table where p_id in (....) order by (weight * 0.8)
I would like to combine these queries to return the r_p_id in ascending order by the sum of (weight from the first query) + (weight from the second query).
Can anybody tell me how to do it?
I'd appreciated it.
Try this
select t1.r_p_id, (t1.weight+t2.m_weight) as total_weight
from
(select r_p_id, weight from table where p_id in (....) ) as t1,
(select r_p_id, (weight*0.8) as m_weight from table where p_id in (....)) as t2
where t1.r_p_id=t2.r_p_id
order by (t1.weight+t2.m_weight)
OR using JOIN keyword
select t1.r_p_id, (t1.weight+t2.m_weight) as total_weight
from
(select r_p_id, weight from table where p_id in (....) ) as t1 INNER JOIN
(select r_p_id, (weight*0.8) as m_weight from table where p_id in (....)) as t2 ON t1.r_p_id=t2.r_p_id
order by (t1.weight+t2.m_weight)
You'l need to use JOIN between results of two queries.
EDIT:
Since MySQL supports order by [alias-name] as dg99 suggested, you can use directly order by total_weight
select t1.r_p_id, (t1.weight+t2.m_weight) as total_weight
from
(select r_p_id, weight from table where p_id in (....) ) as t1,
(select r_p_id, (weight*0.8) as m_weight from table where p_id in (....)) as t2
where t1.r_p_id=t2.r_p_id
order by total_weight
Um, maybe I'm missing something, but wouldn't it just be the following?
select r_p_id, weight, weight*0.8 AS m_weight from table where p_id in (....) order by weight
Mathmatically, you'll get the same order whether you do "order by weight" or "order by weight + 0.8*weight"
select r_p_id, weight, (weight*0,8) as m_weight, (weight*1.8) as total_weight
from table where p_id in (...) order by total_weight asc
weight + weight * .8 = weight * 1.8, so there's a quick sum of that column. Which of the weight columns you order by doesn't matter because they are all the same order

Select the 3 most recent records where the values of one column are distinct

I have the following table:
id time text otheridentifier
-------------------------------------------
1 6 apple 4
2 7 orange 4
3 8 banana 3
4 9 pear 3
5 10 grape 2
What I want to do is select the 3 most recent records (by time desc), whose otheridentifiers are distinct. So in this case, the result would be id's: 5, 4, and 2.
id = 3 would be skipped because there's a more recent record with the same otheridentifier field.
Here's what I tried to do:
SELECT * FROM `table` GROUP BY (`otheridentifier`) ORDER BY `time` DESC LIMIT 3
However, I end up getting rows of id = 5, 3, and 1 instead of 5, 4, 2 as expected.
Can someone tell me why this query wouldn't return what I expected? I tried changing the ORDER BY to ASC but this simply rearranges the returned rows to 1, 3, 5.
It doesn't return what you expect because grouping happens before ordering, as reflected by the position of the clauses in the SQL statement. You're unfortunately going to have to get fancier to get the rows you want. Try this:
SELECT *
FROM `table`
WHERE `id` = (
SELECT `id`
FROM `table` as `alt`
WHERE `alt`.`otheridentifier` = `table`.`otheridentifier`
ORDER BY `time` DESC
LIMIT 1
)
ORDER BY `time` DESC
LIMIT 3
You could join the table on itself to filter the last entry per otheridentifier, and then take the top 3 rows of that:
SELECT last.*
FROM `table` last
LEFT JOIN `table` prev
ON prev.`otheridentifier` = last.`otheridentifier`
AND prev.`time` < last.`time`
WHERE prev.`id` is null
ORDER BY last.`time` DESC
LIMIT 3
I had a similar requirement, but I had more advanced selection criteria. Using some of the other answers I couldn't get exactly what I needed, but I found you can still do a GROUP BY after and ORDER BY like this:
SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t
GROUP BY t.otheridentifier
SELECT * FROM table t1
WHERE t1.time =
(SELECT MAX(time) FROM table t2
WHERE t2.otheridentifier = t1.otheridentifier)
Andomar's answer is probably best in that it doesn't use a subquery.
An alternative approach:
select *
from `table` t1
where t1.`time` in (
select max(s2.`time`)
from `table` t2
group by t2.otheridentifier
)
You can use this query to get correct answer:
SELECT * FROM
(SELECT * FROM `table` order by time DESC)
t group by otheridentifier
what about
SELECT *, max(time) FROM `table` group by otheridentifier
This also:
SELECT * FROM
OrigTable T INNER JOIN
(
SELECT otheridentifier,max(time) AS duration
FROM T
GROUP BY otheridentifier) S
ON S.duration = T.time AND S.otheridentifier = T.otheridentifier.