mysql last 5 records in count status - mysql

booking table
id status
1 booked
1 booked
3 cancelled
2 cancelled
2 booked
1 cancelled
1 cancelled
1 booked
select id, count(status) as tot_cancel
from tbl_booking
where id=1 and status='cancelled';
result will be
id tot_cancel
1 2
BUT I NEED last 5 records of user id = 1 and cancelled count not total table record cancelled

I understand that you want the count of cancelled records over the last 5 records of user 1. It is possibe, but you need a column that defines the ordering of the rows, so it is unambiguous which records are last.
Assuming that such column exists in your table and is called ordering_id, you can do:
select sum(status = 'cancelled') no_cancelled
from (select status from mytable where id = 1 order by ordering_id desc limit 5) t

You can do conditional aggregation with limit clause :
select 1 as id, sum(status = 'cancelled')
from table t
where id = 1
order by ? -- use ordering column instead ?
limit 5;
You can use correlated subquery for all ids :
select t.id, sum(t.status = 'cancelled')
from table t
where t.? in (select t1.?
from table t1
where t1.id = t.id
order by t1.?
limit 5
)
group by t.id;

Related

Get most recent records from the table if a 'ALERT' status is present otherwise most recent record with 'OK' Status - Mysql v5.6.50

In Mysql I have the following table - property_alert_status having columns :
id (primary), propertyId, status, updatedAt
All record - select * from property_alert_status
id
propertyId
status
updatedAt
1
1
ALERT
1658304031
2
2
OK
1658300273
3
3
ALERT
1658312336
4
3
ALERT
1658313979
5
3
OK
1658312336
6
2
OK
1658312336
From the above table, I want to fetch the most recent record for the property based on status. If Status is 'ALERT' then most recent 'ALERT' record otherwise Most recent 'OK' record.
Ex - For propertyId '3' there are three records but most recent alert status is of id 4 so the output for the above propertyId 3 should be:
id
propertyId
status
updatedAt
4
3
ALERT
1658313979
Expected Output should be:
id
propertyId
status
updatedAt
1
1
ALERT
1658304031
4
3
ALERT
1658313979
6
2
OK
1658312336
I have made one query but the output is not as expected:
Select mainStatus.* from (
SELECT *
FROM property_alert_status
ORDER BY
(CASE
WHEN status = "ALERT" THEN 0
ELSE 1
END) ASC, updatedAt DESC
) mainStatus group by propertyId;
Innerquery is giving the right result but when selecting only a single record by grouping propertyId, giving the wrong result.
Inner query giving result:
id
propertyId
status
updatedAt
4
3
ALERT
1658313979
3
3
ALERT
1658312336
1
1
ALERT
1658304031
5
3
OK
1658312336
6
2
OK
1658312336
2
2
OK
1658300273
The final query gives result:
id
propertyId
status
updatedAt
1
1
ALERT
1658304031
2
2
OK
1658300273
3
3
ALERT
1658312236
Note: Using Mysql v5.6.50.
Tables in SQL are unordered data set. A query result is a table. So the ORDER BY clause in your subquery doesn't have to sort the rows. Don't rely on it. Some DBMS even raise an error when you have an ORDER BY at the end of a subquery.
Moreover, select * from ... group by ... is invalid. If you group by a column, you can select that column plus aggregates, i.e. sums, maximums, averages and so on. You cannot select other original column values (except for the case they are functionally dependent on your group, such as a person's name when you group by the person's ID). MySQL should raise an error, and if it doesn't, this probably means that you are working in a cheat mode that MySQL invented in their early days. Make sure to always SET sql_mode = 'ONLY_FULL_GROUP_BY'; when working with MySQL in order to have the DBMS help you with invalid aggregation queries.
As to the task: You can rank your rows with ROW_NUMBER.
SELECT *
FROM
(
SELECT
s.*,
ROW_NUMBER() OVER (PARTITION BY propertyid ORDER BY status, updatedat DESC) AS rn
FROM vk_property_temperature_alert_status s
WHERE temperature_status IN ('ALERT', 'OK')
) ranked
WHERE rn = 1;
For old MySQL versions I see two approaches. Either select only those rows for which not exists a better row or select those rows that are the best for their group. The second approach seems easier. It's basically writing a subquery that determines the top row for the property ID, so you can check whether the row you are looking at is a top row.
SELECT *
FROM vk_property_temperature_alert_status s
WHERE id =
(
SELECT s2.id
FROM vk_property_temperature_alert_status s2
WHERE s2.temperature_status IN ('ALERT', 'OK')
AND s2.propertyid = s.propertyid
ORDER BY s2.status, s2.updatedat DESC
LIMIT 1
);
I don't know if this will work, wrote just for fun as the question was very interesting:
SELECT
MAX(maxId),
propertyId,
`status`,
MAX(dates) updatedAt
FROM
(
SELECT
firstResult.*,
(CASE WHEN #running_propertyId=0 THEN #running_propertyId:=propertyId ELSE #running_propertyId:=#running_propertyId END) runningPro,
(CASE WHEN #running_status='' THEN #running_status:=`status` ELSE #running_status:=#running_status END) runningStat,
(CASE WHEN #running_variable >0 AND #running_propertyId =propertyId THEN #running_variable:=#running_variable+1 ELSE #running_variable:=1 END )var,
(CASE WHEN #running_variable =1 THEN #running_date:=updatedAt ELSE (CASE WHEN `status`='ALERT' THEN #running_date:=updatedAt ELSE
( CASE WHEN #running_status=`status` THEN #running_date:=updatedAt ELSE #running_date:=#running_date END) END) END )dates,
(CASE WHEN #running_variable =1 THEN #running_id:=id ELSE (CASE WHEN `status`='ALERT' THEN #running_id:=id ELSE
( CASE WHEN #running_status=`status` THEN #running_id:=id ELSE #running_id:=#running_id END) END) END )maxId,
#running_propertyId:=propertyId,
#running_status:=`status`
FROM (SELECT
a.*,
#running_propertyId:=0,
#running_status:='',
#running_variable:=0,
#running_date:=0,
#running_id:=0
FROM
property_alert_status a
ORDER BY
`propertyId`
,`updatedAt`) firstResult
) final
GROUP BY propertyId
By combining my query with some changes into the #Thorsten Kettner's query -
Following Query giving expected result:
SELECT
*
FROM
property_alert_status s
WHERE
id = (SELECT
s2.id
FROM
property_alert_status s2
WHERE
s2.propertyId = s.propertyId
ORDER BY (CASE
WHEN s2.status = 'ALERT' THEN 0
ELSE 1
END) ASC, s2.updatedAt DESC
LIMIT 1);

Get the next max(id)

I've got the following table:
booking_id
user_id
11
1
12
76
13
932
14
1
15
626
16
1
17
3232
I want to access the 2nd maximum booking_id for user 1.
The expected result is user_id = 1, booking_id = 14.
I've been working over these hellish flames for way too long, this doesn't do any good:
select booking.user_id, b1.booking_id from booking
left join(select
user_id,
booking_id
from booking
where booking_id = (select
max(booking_id)
from booking
where booking_id <> (select
max(booking_id)
from booking))
group by user_id)
as b1 on b1.user_id = booking.user_id
where booking.user_id = '1'
Please note I've managed to do it as a calculated column but that's useless, I need the derived table.
If you are using MySQL, you can avoid the (rather messy) double sub-query by using LIMIT & OFFSET
Just add order by booking_id desc LIMIT 1 OFFSET 1 and you will get the second highest booking_id. For example ...
select * from booking where user_id = 1 order by booking_id desc OFFSET 1 LIMIT 1
I tested this on one of my tables & it worked fine. If you have an index on booking_id it should be really fast.
If you want the second highest booking for the user who holds the highest booking, then this should work
SELECT * FROM booking
WHERE user_id in
(select user_id from booking order by booking_id desc limit 1)
ORDER BY booking_id DESC LIMIT 1 OFFSET 1
The sub-query finds the user_id of the user with the highest booking, then the main query finds their second highest booking
A simple way to do it is using LIMIT OFFSET:
SELECT *
FROM booking
WHERE user_id = 1
ORDER BY booking_id DESC
LIMIT 1 OFFSET 1
Demo here
By using the answer in this question What is the simplest SQL Query to find the second largest value? https://stackoverflow.com/a/7362165/14491685
you can integrate with your query to get it like this:
select * from booking
where booking_id =
(select max(booking_id) from booking
where user_id =1
and booking_id not in (SELECT MAX(booking_id ) FROM booking ))

filter data based on group completion data

I have a table which contains groups of scheduled programs. Each group is represented by group_id and each program in the group depends on previous program to complete. But, I don't need to schedule anything if all the programs in that group are completed. So, I need to filter data if a group containing programs are all completed. order defines the order of the programs that need to be scheduled
id, group_id, trigger_group_id, trigger, order
1 1 NULL SCHEDULED 0
2 1 1 COMPLETED 1
3 1 1 SCHEDULED 2
4 2 NULL COMPLETED 0
5 2 1 COMPLETED 1
How to filter data such that group 2 rows are not returned using mysql?
Select the last row of a group in a correlated subquery and compare the trigger value:
select *
from mytable t
where 'SCHEDULED' = (
select `trigger`
from mytable t2
where t2.group_id = t.group_id
order by t2.id desc
limit 1
)
Demo: http://sqlfiddle.com/#!9/976d5/1

How get the last inserted row for an employee's transactions and the last "previous" one with a specific status?

I have a table of data like:
TransId EmpId Status Time
...other employees...
2 3 'action6' 1479166669
3 3 'action2' 1479166670
...other employees...
6 3 'action3' 1479166673
...other employees...
9 3 'action4' 1479166678
...other employees...
14 3 'action5' 1479166685
...other employees...
I want to do a MySQL query that gives me the top row (transId = 14) AND the last row for this employee prior to the top row that had the status 'action6' (transId = 2).
How would I put that in one query? I do not want to use a sub-query if possible.
You can use the following union to combine your two rows:
(select * from yourtable
where EmpId = yourempid
order by TransId desc limit 1)
union
(select * from yourtable
where EmpId = yourempid
and TransId <> (select max(TransId)
from yourtable
where EmpId = yourempid)
and Status = 'action6'
order by TransId desc limit 1)
order by TransId;
Make sure you have an index for (EmpId, TransId), and optionally additionally (EmpId, Status, TransId).
You should not worry about subqueries. An independent subquery (that doesn't depend on the row) will only get calculated once (and in this case by a single index lookup).

How to select only the last value in a query in MySQL?

How can I select on MySQL the last value of this result:
This is a result from query:
SELECT * from transaction WHERE transaction_id = 2
I just need the last value 3 300 2
bank_id amount transaction_id
1 800 2
3 50 2
3 300 2
If bank_id is not unique and you want to pick the record of highest amount first, you can try this one:
SELECT *
FROM transaction
WHERE transaction_id = 2
ORDER BY bank_id DESC
, amount DESC
LIMIT 1
See this SQLFiddle
SELECT *
FROM transaction
WHERE transaction_id = 2
ORDER BY bank_id desc
LIMIT 1
Here is SQLFiddel Demo
This Demo, selects Last Entry in Transaction table with your filter of Transaction_ID = 2.
Below is the Query which you can try.
select *,#curRow := #curRow + 1 AS row_number
from Temp
Join (SELECT #curRow := 0) r
where Transaction_id = 2
order by row_number desc
limit 1
try out this..
SELECT *
FROM transaction
WHERE transaction_id = 2
ORDER BY transaction_id DESC
LIMIT 1