Count total number of occurrence of two consecutive values in a table - mysql

My table structure
+----+--------+
| id | status |
+----+--------+
| 1 | 10 |
| 2 | 21 |
| 3 | 22 |
| 4 | 29 |
| 5 | 30 |
| 6 | 32 |
| 7 | 33 |
| 8 | 21 |
| 9 | 22 |
| 10 | 23 |
| 11 | 21 |
| 12 | 22 |
| 13 | 23 |
+----+--------+
I want to count total number of times when status 22 comes just after status 21.
In this case the query should return 3.
sql fiddle

Just use a Self Join with Conditional Aggregate
SELECT Sum(CASE WHEN a.status = 22 AND b.status = 21 THEN 1 END) As Stat_Count
FROM testTable a
LEFT OUTER JOIN testTable b
ON a.id = b.id + 1
SQLFIDDLE DEMO

If you can have gaps in your id's you can use a subquery to check whether the previous status of a 22 row is 21
select count(*)
from testtable a
where a.status = 22 and (select status from testtable b
where b.id < a.id order by id desc limit 1) = 21
http://sqlfiddle.com/#!2/9d567/2
Another way gets all id's of previous rows of rows with a status of 22 in derived table and then joins the ids to count how many have a status of 21
select count(*) from (
select max(b.id) max_b_id
from testtable a join testtable b on b.id < a.id
where a.status = 22
group by a.id
) t1 join testtable a on a.id = t1.max_b_id
where a.status = 21

I have tried to solve it in php
$q="";
$q= mysqli_query("select *from testTable");
while($r=mysqli_fetch_assoc($q)){
$rows[]=$r;
}
$success=0;
for ($i=0;$i<count($rows);$i++){
if($rows[$i]['status']==21 and $rows[$i+1]['status']==22 ){
$success+=1;
}
}
echo $success;

Related

selecting only newest row with specific value

Table:
person | borrow_date | is_borrowed | SN | date | id
1 | 2019-01-10...| 1 | 20 |2019-01-10...| 6
3 | 2019-01-09...| 3 | 10 |2019-01-09...| 5
1 | 2019-01-08...| 1 | 10 |2019-01-08...| 4
2 | 2019-01-08...| 1 | 10 |2019-01-08...| 3
1 | NULL | 2 | 20 |2019-01-07...| 2
1 | NULL | 2 | 10 |2019-01-07...| 1
My wanted output is to select newest rows where "is_borrowed" equals 1 and grouped by SN, so that when the query is executed with person=2 or person=3 then it would retrieve empty set. Whereas for person=1 it would give back two rows.
Wanted output (where person=1):
person | borrow_date | is_borrowed | SN | date |id
1 | 2019-01-10...| 1 | 20 | 2019-01-10...|6
1 | 2019-01-08...| 1 | 10 | 2019-01-08...|4
Wanted output (where person=2):
EMPTY SET
Wanted output (where person=3):
EMPTY SET
This is my current query and it sadly doesn't work.
SELECT a.SN, a.is_borrowed,a.max(date) as date, a.person
FROM table a
INNER JOIN (SELECT SN, MAX(date) as date, osoba from table where person like
"2" group by SN) as b
ON a.SN=b.SN and a.date=b.date
WHERE a.person like "2" and a.is_borrowed=1
If I correctly understood you from the question and the comment you made under it, here's one way to do it without specifying the person:
select *
from TableName as p
inner join (select max(borrow_date) as borrow_date,
SN
FROM TableName
where is_borrowed = 1
group by SN) as p2
on p.borrow_date = p2.borrow_date and p.SN = p2.SN
This should give you the result you're looking for. Here's a demo.
Note that I had to change the borrowed_date values in the table since yours contain hours and minutes while I didn't add those.
You can always specify it for each person by adding a where clause after the join.
select p.person,
p.borrow_date,
p.is_borrowed,
p.SN,
p.date,
p.id
from TableName as p
inner join (select max(borrow_date) as borrow_date,
SN
FROM TableName
where is_borrowed = 1
group by SN) as p2
on p.borrow_date = p2.borrow_date and p.SN = p2.SN
where p.person = '1'
Output:
person | borrow_date | is_borrowed | SN | date | id
1 | 2019-01-10 | 1 | 20 | 2019-01-10 | 6
1 | 2019-01-08 | 1 | 10 | 2019-01-08 | 4
While where p.person = '2' and where p.person = '3' will return empty sets.

select count only showing 1 result and the wrong one

I want to search TABLE1 and count which number_id has the most 5's in experience column.
TABLE1
+-------------+------------+
| number_id | experience |
+-------------+------------+
| 20 | 5 |
| 20 | 5 |
| 19 | 1 |
| 18 | 2 |
| 15 | 3 |
| 13 | 1 |
| 10 | 5 |
+-------------+------------+
So in this case it would be number_id=20
Then do an inner join on TABLE2 and map the number that matches the number_id in TABLE1.
TABLE2
+-------------+------------+
| id | number |
+-------------+------------+
| 20 | 000000000 |
| 29 | 012345678 |
| 19 | 123456789 |
| 18 | 223456789 |
| 15 | 345678910 |
| 13 | 123457898 |
| 10 | 545678910 |
+-------------+------------+
So the result would be:
000000000 (2 results of 5)
545678910 (1 result of 5)
So far I have:
SELECT number, experience, number_id, COUNT(*) AS SUM FROM TABLE1
INNER JOIN TABLE2 ON TABLE1.number_id = TABLE2.id
WHERE experience = '5' order by SUM LIMIT 10
But it's returning just
545678910
How can I get it to return both results and by order of number of instances of 5 in the experience column?
Thanks
This query will give you the results that you want. The subquery fetches all the number_id that have experience values of 5. The SUM(experience=5) works because MySQL uses a value of 1 for true and 0 for false. The results of the subquery are then joined to table2 to give the number field. Finally the results are ordered by the number of experience=5:
SELECT t2.number, t1.num_fives
FROM (SELECT number_id, SUM(experience = 5) AS num_fives
FROM table1
WHERE experience = 5
GROUP BY number_id) t1
JOIN table2 t2
ON t2.id = t1.number_id
ORDER BY num_fives DESC
Output:
number num_fives
000000000 2
545678910 1
SQLFiddle Demo
Add a group by clause:
SELECT number, experience, number_id, COUNT(*) AS SUM
FROM TABLE1
JOIN TABLE2 ON TABLE1.number_id = TABLE2.id
WHERE experience = '5'
GROUP BY 1, 2, 3 -- <<< Added this clause
ORDER BY SUM
LIMIT 10

How to select rows, using group by with minimum field values?

Today I have posted a question and got a good answer: Stuck in building mysql query.
I though it helped me, but I've discovered that it returns wrong data. So I'm reposting the question here, with an answer I received, as well I will explain the problem why it is not working for me.
Example of data:
id | item_id | user_id | bid_price
----------------------------------
1 | 1 | 11 | 1
2 | 1 | 12 | 2
3 | 1 | 13 | 3
4 | 1 | 14 | 1
5 | 1 | 15 | 4
6 | 2 | 16 | 2
7 | 2 | 17 | 1
8 | 3 | 18 | 2
9 | 3 | 19 | 3
10 | 3 | 18 | 2
Expected result:
id | item_id | user_id | bid_price
----------------------------------
1 | 1 | 11 | 1
7 | 2 | 17 | 1
8 | 3 | 18 | 2
Offered solution:
select m.id, m.item_id, m.user_id, m.bid_price
from my_table m
inner join (
select item_id, min(id) min_id, min(bid_price) min_price
from my_table
where item_id IN (1,2,3)
group by item_id
) t on t.item_id = m.item_id
and t.min_price= m.bid_price
and t.min_id = m.id
The problem:
In the sub query the minimum ID is selected entire the group by (item_id) statement and doesn't reflects according to minimum bid_price.
In other words, the minimum id is selected not depending on the price field at all. So, in the result I will get minimum price and minimum id of the group, but this will not be the same row! The id can be related to the row with another bet_price value.
How this query can be adjusted? Thank you in advance!
SELECT min(m.id) AS id, m.item_id, m.user_id, m.bid_price
FROM my_table m
INNER JOIN (
SELECT item_id, min(bid_price) AS min_price
FROM my_table
GROUP BY item_id
) t ON t.item_id = m.item_id
AND t.min_price= m.bid_price
GROUP BY item_id
Output
id item_id user_id bid_price
1 1 11 1
7 2 17 1
8 3 18 2
Live Demo
http://sqlfiddle.com/#!9/a52dc6/13
SELECT DISTINCT
t1.item_id,
t1.bid_price
FROM tab1 t1
WHERE NOT exists(SELECT 1
FROM tab1 t2
WHERE t2.item_id = t1.item_id
AND t2.bid_price < t1.bid_price)
AND t1.item_id IN (1, 2, 3);
http://sqlfiddle.com/#!9/615e0a/5

Return unique rows of records for each user

I have a table that tracks different qualifications for students. The qualifications are renewed periodically, so many students have multiple records for the same qualification.
I'm trying to return just the most recent record of each qualification for each student, without the duplicates.
So far I have this, but I'm stuck on what I need to do to remove the duplicate type_scrn and just return the most recent records.
SELECT scrn.*
FROM cert_scrn scrn
WHERE scrn.id_scrn = (SELECT scrn2.id_scrn
FROM cert_scrn scrn2
WHERE scrn.id_scrn = scrn2.id_scrn
AND ( scrn2.type_scrn = 1
OR scrn2.type_scrn = 11
OR scrn2.type_scrn = 12
OR scrn2.type_scrn = 13 )
ORDER BY scrn2.expiredate_scrn DESC LIMIT 1)
ORDER BY scrn.idstu_scrn
This returns:
id_scrn | idstu_scrn | type_scrn | expiredate_scrn
-------------------------------------------------
15 | 58 | 1 | 2010-01-26
1539 | 58 | 1 | 2015-06-21
5790 | 58 | 11 | 2016-02-20
5791 | 58 | 12 | 2016-02-20
5792 | 58 | 13 | 2016-02-20
What I need returned:
id_scrn | idstu_scrn | type_scrn | expiredate_scrn
---------------------------------------------------
1539 | 58 | 1 | 2015-06-21
5790 | 58 | 11 | 2016-02-20
5791 | 58 | 12 | 2016-02-20
5792 | 58 | 13 | 2016-02-20
You need to join to a subquery which finds the max date for each idstu_scn, type_scrn group.
So your query to get the max(date) would be:
select idstu_scrn, type_scrn, max(expiredate_scrn) mdate
from cert_scrn
group by idstu_scrn, type_scrn
Which we then just need to join back to the cert_scrn table again, to find the rest of the details to go along with it.
select scrn.*
from cert_scrn scrn
inner join (
select idstu_scrn, type_scrn, max(expiredate_scrn) mdate
from cert_scrn
group by idstu_scrn, type_scrn ) q
on scrn.idstu_scrn = q.idstu_scrn and scrn.type_scrn = q.type_scrn and scrn.expiredate_scrn = q.mdate
where scrn.type_scrn = 1
or scrn.type_scrn = 11
or scrn.type_scrn = 12
or scrn.type_scrn = 13
demo fiddle here
Please check this one based on Primary Key, appears working fine for this scenario :
SELECT * FROM cert_scrn WHERE id_scrn IN
(SELECT MAX(id_scrn) FROM cert_scrn GROUP BY idstu_scrn, type_scrn);

Latest Group By MYSQL + link Table [duplicate]

This question already has answers here:
Retrieving the last record in each group - MySQL
(33 answers)
GROUP BY characteristic in mysql [closed]
(1 answer)
Closed 9 years ago.
I'm experiencing trouble with the a linking table and retrieving the lastUsed values.
Linking table:
link_devices_user
id | deviceId | shopId |
1 | 359 | 46 |
2 | 1339 | 46 |
3 | 1328 | 45 |
4 | 882 | 46 |
system_devices
id | carId | registerId | lastUsed |
359 | 350 | regi1 | 2014-01-03 09:00:00 |
1339 | 350 | regi2 | 2013-01-03 09:00:00 |
1328 | 160 | regi3 | 2012-01-03 09:00:00 |
882 | 150 | regi4 | 2014-01-03 08:59:00 |
Now I need to retrieve the latest unique carId from system_devices that is connected to shopId 46.
So in this case, the results should be.
882 | 150 | regi4 | 2014-01-03 08:59:00 |
359 | 350 | regi1 | 2014-01-03 09:00:00 |
I now have the following query. This gives me the unique carId but not the latest unique carId. What should i change?
SELECT system_devices.id,
carId,
FROM link_devices_user
INNER JOIN system_devices
ON link_devices_user.deviceId = system_devices.id
WHERE link_devices_user.shopid = '46'
GROUP BY system_devices.carId
ORDER BY system_devices.lastUsed DESC
Try this:
SELECT s.*
FROM system_devices s LEFT JOIN system_devices s1
ON (s.carId = s1.carId AND s.lastUsed < s1.lastUsed)
INNER JOIN link_devices_user ld ON s.id = ld.deviceId
WHERE (s1.id IS NULL) AND (ld.shopId = 46)
ORDER BY carId
http://sqlfiddle.com/#!2/158d9/4
You can check the SQL fiddle sample provided that gives the results required.
Try this:
SELECT A.id, A.carId, A.registerId, A.lastUsed
FROM (SELECT sd.id, sd.carId, sd.registerId, sd.lastUsed
FROM system_devices sd
INNER JOIN link_devices_user ld ON sd.id = ld.deviceId
WHERE ld.shopId = 46
ORDER BY sd.id, sd.carId DESC
) AS A
GROUP BY A.id
OR
SELECT sd.id, sd.carId, sd.registerId, sd.lastUsed
FROM system_devices sd
INNER JOIN link_devices_user ld ON sd.id = ld.deviceId
INNER JOIN (SELECT id, MAX(carId) carId FROM system_devices GROUP BY id) A ON A.id = sd.id AND A.carId = sd.carId
WHERE ld.shopId = 46
ORDER BY sd.id