MySQL Query to find users still inside room - mysql

Below is my database table, where I will have Check In and Check Out entry records for attending the conference room.
id registration_id roomno day type
1 101 1 2 In
2 103 1 2 In
3 101 1 2 Out
4 105 1 2 In
5 103 1 2 Out
6 101 1 2 In
7 103 1 2 In
8 101 1 2 Out
9 105 1 2 In
10 103 1 2 Out
Now, I want to select those records, which are still attending the conference. Condition is like their last record should be type = In. There can be multiple In/Out entries for each user during a day.
Please let me know the quickest possible MySQL query.
Thanks
Answer which I ended up using:
select * from `registrations_inouts` t
group by t.registration_id
having max(id) = max(case when type = 'In' then id end)
order by rand() limit 1;

Here is one method using not exists:
select *
from t
where t.type = 'In' and
not exists (select 1
from t t2
where t2.registration_id = t.registration_id and t2.type = 'Out'
);
Another method uses conditional aggregation:
select t.registration_id
from t
group by t.registration_id
having max(id) = max(case when type = 'In' then id end);
Note: both of these assume that the ids are assigned sequentially in time, so larger ids are later in time.

Related

SQL QUERY - how to get child records with different types but from the same parent group

I needed a query where to return the finished type records from the service_flow_actions table, but the records must belong to the service_flow table group where there are records that were given play
Table work_order
id
company_id
closed
status
1
1
true
true
2
1
true
true
Table service_flow
id
work_order_id
company_id
1
1
1
2
2
1
3
2
1
Table service_flow_actions
id
work_order_id
service_flow_id
type
company_id
1
1
1
finished
1
2
1
2
play
1
3
2
2
finished
1
4
2
3
play
1
5
2
3
pause
1
6
2
3
finished
1
I had thought of something like that, but it didn't work.
SELECT DISTINCT(service_flow_actions.*)
FROM service_flow_actions
INNER JOIN work_order ON service_flow_actions.work_order_id = work_order.id
LEFT JOIN service_flow_actions t ON work_order.id = t.work_order_id AND t.type = 'play' AND work_order.company_id = 37
WHERE work_order.company_id = 37 AND service_flow_actions.type = 'finished' AND work_order.closed = true AND work_order.status = true
The exists clause helps in such situation, of course you can achieve the same result using the join clause, but I would go for simple solution first, unless I face performance issues.
SELECT *
FROM service_flow_actions
WHERE type = 'finished'
AND EXISTS (
SELECT 1
FROM service_flow_actions sub
WHERE sub.service_flow_id = service_flow_actions.service_flow_id
AND sub.type = 'play'
)

configure query to bring rows which have more than 1 entries

How to get those entries which have more than 1 records?
If it doesn't make sense... let me explain:
From the below table I want to access the sum of the commission of all rows where type is joining and "they have more than 1 entry with same downmem_id".
I have this query but it doesn't consider more entries scenario...
$search = "SELECT sum(commission) as income FROM `$database`.`$memcom` where type='joining'";
Here's the table:
id mem_id commission downmem_id type time
2 1 3250 2 joining 2019-09-22 13:24:40
3 45 500 2 egbvegr new time
4 32 20 2 vnsjkdv other time
5 23 2222 2 vfdvfvf some other time
6 43 42 3 joining time
7 32 353 5 joining time
8 54 35 5 vsdvsdd time
Here's the expected result: it should be the sum of the id no 2, 7 only
ie. 3250+353=whatever.
It shouldn't include id no 6 because it has only 1 row with the same downmem_id.
Please help me to make this query.
Another approach is two levels of aggregation:
select sum(t.commission) income
from (select sum(case when type = 'joining' then commission end) as commission
from t
group by downmem_id
having count(*) > 1
) t;
The main advantage to this approach is that this more readily supports more complex conditions on the other members of each group -- such as at most one "joining" record or both "joining" records and no more than two "vnsjkdv" records.
Use EXISTS:
select sum(t.commission) income
from tablename t
where t.type = 'joining'
and exists (
select 1 from tablename
where id <> t.id and downmem_id = t.downmem_id
)
See the demo.
Results:
| income |
| ----- |
| 3603 |
You can use subquery that will find all downmem_id having more than one occurrence in the table.
SELECT Sum(commission) AS income
FROM tablename
WHERE type = 'joining'
AND downmem_id IN (SELECT downmem_id
FROM tablename t
GROUP BY downmem_id
HAVING Count(id) > 1);
DEMO

Select query result inside WHERE clause

Hello I am trying to make a WHERE clause where the condition is the id of the previous selection, example:
SELECT
,P1.caseid
,(SELECT SUM(P1.amount) FROM table_s P1 WHERE P1.status = 4 AND P1.caseid = 20)
as variable
FROM table_s P1 GROUP BY P1.caseid";
let's say each iteration the P1.caseid have value of
20,
45,
20,
How I can insert this value to be the condition of the WHERE clause here: WHERE P1.status = 4 AND P1.caseid = 20
Instead of P1.caseid to be = to 20 it have to be equal to the actual caseid inside the database for each row.
So for each row it will be:
WHERE P1.caseid = 20
WHERE P1.caseid = 45
WHERE P1.caseid = 35
In this case the number is eqaul to the caseid inside the DB.
TABLE NAME: table_s
id | caseid | amount | status
-- | ------------------------
1 | 20 | 10 | 4
2 | 45 | 10 | 4
3 | 20 | 10 | 4
DB is as follows, the result should be:
1 ROW = caseid: 20 amount: 20 status 4
2 ROW = caseid: 45 amount: 10 status 4
Or
$variable = 20
$variable = 10
I think I've worked out what you're asking...
The important note here is to use different aliases for your table in the outer and inner queries. Otherwise you have a serious scope problem. (If two instances of the same entity have the same name, how can MySQL ever know which one you're referring to? It will choose the one in the nearest scope. So, instead, call one of them, for example, lookup.)
SELECT
P1.*,
(
SELECT SUM(lookup.amount)
FROM table_s lookup
WHERE lookup.status = 4
AND lookup.caseid = P1.caseid
)
correlated_sub_query_total_by_caseid
FROM
table_s P1
But that itself can be re-written without the correlated sub-query...
SELECT
P1.*,
SUM(CASE WHEN status = 3 THEN amount END) AS status_3_total,
SUM(CASE WHEN status = 4 THEN amount END) AS status_4_total
FROM
table_s P1
INNER JOIN
table_s lookup
ON lookup.caseid = P1.caseid
GROUP BY
P1.primary_key
That said, you added another comment that seems to contract your question...
the idea is to select the sum of the amount for each caseid and display it. as caseid - sum
For that you just need an aggregation...
SELECT
caseid,
SUM(amount)
FROM
table_s
GROUP BY
caseid
And if you only want to aggregate where the status is 3 or 4...
SELECT
caseid,
SUM(CASE WHEN status = 3 THEN amount ELSE 0 END) status_3_total
SUM(CASE WHEN status = 4 THEN amount ELSE 0 END) status_4_total
FROM
table_s
GROUP BY
caseid

Count distinct values on 2 colums when using GROUP BY

Considering the following query:
SELECT t.recording_id, m.release_id
FROM track t
JOIN medium m ON t.medium_id = m.medium_id
i get a result set similar to this one
recording id release id
----------------------------------
1 25
1 25
1 37
1 76
1 300
1 336
2 37
... ...
i need to output the following
recording id count
---------------------------------------------------
1 5
2 1
In other words, i need to group by the recording_id but not count the release_id duplicates for that recording_id
After researching this board i've tried the following, with no success :
SELECT t.recording_id, count(t.recording_id)
FROM track t
JOIN medium m ON t.medium_id = m.medium_id
group by t.recording_id, m.release_id
but, im getting
recording id release id
--------------------------
1 2
1 1
1 1
1 1
1 1
2 1
What's wrong?
Try this, you can use distinct in your count function to return distinct release ids for a recording_id
SELECT t.recording_id, count(distinct m.release_id) cnt
FROM track t
JOIN medium m ON t.medium_id = m.medium_id
group by t.recording_id

Selecting a count on two separate conditions

Let's say I have the following data.
id name_id completed
1 10 1
2 10 0
3 15 1
4 10 0
5 20 1
6 15 0
7 20 1
8 15 0
I'm trying to find a count by the name id, which is pretty simple
SELECT name_id, COUNT(*) FROM db
GROUP BY name_id
Now, I have a second component which I want to include in the query.
For name_id 10, I want to count just those values where completed is 1. For the other name_id's, I want to select them regardless of whether they are 0 or 1.
So I should end up with:
name_id count(*)
10 1
15 3
20 2
Name_id 10 only has a count of 1 because it's just the 1 which is completed, while the other counts include both 0 and 1.
Can anyone help with this task.
Thanks!
You can use a CASE expression inside of your aggregate function.
SELECT name_id,
sum(case
when name_id = 10
then case when completed = 1 then 1 else 0 end
else 1 end) Total
FROM db
GROUP BY name_id;
See SQL Fiddle with Demo.
Exclude the rows where name_id = 10 and completed = 0:
SELECT name_id, COUNT(*) FROM db
WHERE NOT (completed = 0 AND name_id = 10)
GROUP BY name_id
SELECT name_id, COUNT(*) FROM db
WHERE name_id != 10 or completed = 1
GROUP BY name_id
Count when name_id is not 10. If it is 10, count when completed = 1:
SELECT
name_id,
COUNT(CASE WHEN name_id <> 10 or completed = 1 THEN 1 END)
FROM db
GROUP BY name_id