How to check how many time a car is parked on - mysql

I need a report of which cars (license plates) are parked in and when.
This is an example of my table.
id lic_plate datetime lane
_________________________________________________
10 1234-JM 2022-10-07 12:24:33 IN
11 1234-JM 2022-10-07 12:29:57 OUT
12 5678-PC 2022-10-07 15:14:17 IN
So when I query which are those who are parked more than - for instance - 1hour, the result Now (2022-10-07 15:14:17) should be "5678-PC".
I have tried:
SELECT lic_plate, COUNT(*) AS result
FROM table
GROUP BY lic_plate
HAVING COUNT(lane='IN') AND COUNT(lane='OUT')
But I can't figure out where I insert the HOUR query. And it seems to me that this kind of solution will have some "hidden" flaws.
What will be the best approach?
Thanks in advance.

select max(id) as id
,lic_plate
,max(datetime) as datetime
,timediff(now(),max(datetime)) as time_parked
from t
group by lic_plate
having count(*)%2 != 0
id
lic_plate
datetime
time_parked
12
5678-PC
2022-10-07 15:14:17
69:26:12
Fiddle

We check the time difference between the current date and time and datetime. We count how many records we have per car and if we have even numbers of records we filter the results as we know the car is out already.
select id
,lic_plate
,datetime
,time_parked
from (
select *
,count(*) over(partition by lic_plate) as chk
,timediff(now(),datetime) as time_parked
from t
) t
where chk%2 != 0
id
lic_plate
datetime
time_parked
12
5678-PC
2022-10-07 15:14:17
00:29:58
Fiddle

Related

MySQL - Iterate Through Table

I'm trying to figure out how I can iterate through a table to get a count of how many days an id is not in an Active status.
Say I have the following table:
id
Status
Date
1
Active
1/15/21
1
Inactive
1/13/21
1
Active
1/12/21
1
Inactive
1/9/21
1
Active
1/7/21
2
Active
1/5/21
2
Inactive
1/4/21
2
Inactive
1/2/21
2
Active
1/1/21
The desired output for this example should be:
id
Days Inactive
1
5
2
3
I would like to do a DATEDIFF() when the status changes from Active to Inactive.
I can't just do a SELECT for Status <> Active and do a DATEDIFF() on the MAX and MIN dates in the range because it could go ACTIVE in between that range which would make the count different as seen in the example table.
I think I need a LOOP and/or CURSOR with a variable that gets added to as the count grows for each id, I'm just not sure exactly how to execute that.
Any suggestions or ideas are much appreciated!
Try this:
SELECT id,count(*) as days_inactive FROM table
WHERE status like 'inactive'
GROUP BY id
You can achieve what you want using variables. Just calculate the number of days from the previous date if and only if the id is the same and the current row is an active status, as follows.
select #id :=0, #lastDate := null;
select id, sum(DaysInactive) as DaysInactive
from (
select id, (case when id = #id and status='Active' then datediff(tranDate, #lastDate) else 0 end) as DaysInactive
, #id := id, #lastDate := tranDate
from tablename
order by id, TranDate
) as calc group by id
You can run the inner select separately to confirm that your calculations are correct. It should also work if your table has consecutive 'Inactive' or 'Active' statuses.
Adjust the above for your table and column names.

Grouping up a row in SQL to show the number of distinct occurrences

I have the following SQL query that shows the number of clusters active for my users. For every 1 license_key, there are n-number of cluster_ids.
select cluster_id, license_key, created_time
from events
where created_time >= '2018-11-04' and created_time < '2018-12-03'
and event_name = 'cluster-ping'
group by cluster_id
order by license_key
This is the data:
cluster_id license_key created_at
___________________________________________|_______________|___________________
6D677C4196DB3C1BA84AEBC55CAEE527DDE498C7 111111111111 2018-11-26 17:17:22
CF7BF31A592030E90DAA2BADD632537FA58CD53A 222222222222 2018-11-09 16:55:38
E9A191A125C6632A87629F13E4532C7D09F6C3EE 333333333333 2018-11-24 09:49:48
B92B9F4CE642638CA71829878D27A68E4B831695 444444444444 2018-11-27 19:44:20
26BDDC912E942CC7347D26CA4D72E28E91348E41 555555555555 2018-11-11 14:10:33
F9ABEBEC93C1181635EDE2A1636D709DFD4D8E13 666666666666 2018-11-21 22:06:06
C7664728E8D0C9CAAD1ECC232DADCE00952412BC 666666666666 2018-11-20 18:04:10
FB716F791CB2C2767DB6DE74CD064E95C1A129EA 777777777777 2018-11-18 11:15:30
B5E6EF80FCBA3D3F4CFBD3E7E0477B8E5232CD05 888888888888 2018-11-18 21:08:05
1B1D17334FADBB4D739CE4A940F63E404014A05C 999999999999 2018-11-24 14:00:07
I have the cluster_ids grouped up because of the cluster-ping event that phones home from a cluster every 6 hours. Grouping them up ensures I only get one cluster-ping which indicates one active cluster, instead of all of that one cluster's cluster-pings, which can be numerous per cluster depending how long a cluster is alive.
I want to edit this query I know the number of times the same license_key shows up more than once. As you can see in the sample data above, the license key 666666666666666 shows up twice. I'd like to know in the report the number of times a license_key has n-number of cluster_id.
I have tried to use count(license_key) instead of license_key, but.. that obviously did not work.
Apologies -- new to SQL.
try this:
SELECT license_key, count(cluster_id)
FROM (SELECT cluster_id, license_key, created_time
FROM events
WHERE created_time >= '2018-11-04'
AND created_time < '2018-12-03'
AND event_name = 'cluster-ping'
GROUP BY cluster_id
ORDER BY license_key )
GROUP BY license_key

SQL group by, how to define which record for each group, eg. the latest, is used

I have a table that stores a reference for each product-identifier, however there are some duplicate records - ie. a product may have been submitted more than once so has more than one reference. Each record is timestamped with the updated column.
I need a query that will only give one (non-empty) reference per product-identifier but that crucially will only select the LATEST record for each product.
So if the original table is this:
id updated product-identifier reference
------------------------------------------------------------
1 2014-11-10 07:47:02 9876543210123 98043hjdww98324322
2 2014-11-10 07:53:24 9897434243242 89f7e9wew329f080re
3 2014-11-12 10:51:10 9876543210123 48308402jfjewkfwek
4 2014-11-12 12:53:24 9876543210123 89739432bkjfekwjfk
5 2014-11-12 12:55:16 9876543210321 21321hhfioefhewfoe
6 2014-11-13 01:01:10 9897434243242
7 2014-11-13 01:05:24 9897434243242 1232423jhdksffewfe
The query should return just these records:
id updated product-identifier reference
------------------------------------------------------------
4 2014-11-12 12:53:24 9876543210123 89739432bkjfekwjfk
5 2014-11-12 12:55:16 9876543210321 21321hhfioefhewfoe
7 2014-11-13 01:05:24 9897434243242 1232423jhdksffewfe
I have tried
SELECT * FROM tablename WHERE reference !='' GROUP BY product-identifier ORDER BY updated DESC
and this gives only one record for each product, but not the latest - it is grouping before sorting.
Help greatly appreciated!
I usually do this by having a subquery that selects the highest timestamp for each group (product_identfier in your case) and then use that to select the row I want. Like this
select *
from tablename a
where a.updated = (select max(updated)
from tablename b
where a.product_identifier = b.product_identifier)
There are many ways to do this. If you want the latest record, here is a method using not exists:
select t.*
from tablename t
where not exists (select 1
from tablename t2
where t2.product_identifier = t.product_identifier and
t2.updated > t.updated
);

Checking consecutive values at a MySQL query

I have a MySQL table like this:
ID - Time - Value
And I'm getting every pair of ID, Time (grouped by ID) where Value is greater than a certain threshold. So basicaly, I'm getting every ID which has at least one time a value greater than the threshold. The query looks like this:
SELECT ID, Time FROM mydb.MYTABLE
WHERE Value>%s AND Time>=%s AND Time<=%s
GROUP BY ID
EDIT: The Time checks allow to operate in a time range of my choice between all the data which is into the table; it has nothing else to do with what I am asking.
It works perfectly, but now I want to add some filtering: I want it to avoid those times the value is greater than the threshold (let's call it alarms) if the alarm hasn't happened also the Time just before or just after. I mean: if the alarm accurs at a single, isolated instant of time instead of two consecutive instants of time, I'll consider it is a false alarm and avoid it to be returned at the query response.
Of course I can do this with a call for each Id to check for this, but I'd like to do this in a single query to make it faster. I guess I could use conditionals, but I don't have that expertise at MySQL.
Any help?
EDIT2: Example for Threshold = 10
ID - Time - Value
1 - 2004 - 9
1 - 2005 - 11
1 - 2006 - 8
2 - 2107 - 12
2 - 2109 - 13
3 - 3402 - 11
3 - 3403 - 12
In this example, only ID 3 should be a valid alarm, since 2 consecutive time values for this ID have their value > threshold. ID 1 has a single, isolated alarm, so it should be filteres. For ID 2 there are 2 alarms, but not consecutive, so it should be also filtered.
Something like this:
10 - is a threshold
0 - minimum of the time period
100000 - maximum of the time period
select ID, min(Time)
from
(
SELECT ID, Time,
(select max(time) from t
where Time<t1.Time
and Id=t1.Id
and Value>10) LAG_G,
(select max(time) from t
where Time<t1.Time
and Id=t1.Id
and Value<=10) LAG_L,
(select min(time) from t
where Time>t1.Time
and Id=t1.Id
and Value>10) LEAD_G,
(select min(time) from t
where Time>t1.Time
and Id=t1.Id
and Value<=10) LEAD_L
FROM t as t1
WHERE Value>10 AND Time>=0 AND Time<=100000
) t3
where ifnull(LAG_G,0)>ifnull(LAG_L,0)
OR
ifnull(LEAD_G,100000)<ifnull(LEAD_L,100000)
GROUP BY ID
SQLFiddle demo
This query works for searching near records.
If you need to search records by Time (+1, -1 ) as you've mentioned in the comment try this query:
select ID, min(Time) from t as t1
where Value>10
AND Time>=%s2 AND Time<=%s1
and
(
Exists(select 1 from t where Value>10
and Id=t1.Id
and Time=t1.Time-1)
OR
Exists(select 1 from t where Value>10
and Id=t1.Id
and Time=t1.Time+1)
)
group by ID
SQLFiddle demo
such alarm ?
SELECT ID, Time , count(if(value>%treshold ,1,0)) alert_active
FROM mydb.MYTABLE
WHERE Value>%s3 AND Time>=%s2 AND Time<=%s1
GROUP BY ID;
i don't understand exactly:
In this example, only ID 3 should be a valid alarm, since 2
consecutive time values for this ID have their value > threshold. ID 1
has a single, isolated alarm, so it should be filteres. For ID 2 there
are 2 alarms, but not consecutive, so it should be also filtered.
I guess that You want filter alerts:
SELECT ID, Time
FROM mydb.MYTABLE
WHERE Value>%s3 AND Time>=%s2 AND Time<=%s1
GROUP BY ID
having value<%treshold;

Given a date find the previous &/or current and next x# Dates in MySQL non-linear

I have a table code_prices that looks something like this:
CODE | DATE | PRICE
ABC | 25-7-2011 | 2.81
ABC | 23-7-2011 | 2.52
ABC | 22-7-2011 | 2.53
ABC | 21-7-2011 | 2.54
ABC | 20-7-2011 | 2.58
ABC | 17-7-2011 | 2.42
ABC | 16-7-2011 | 2.38
The problem with the data set is there are gaps in the dates, so I may want to look for the price of item ABC on the 18th however there is no entry because the item wasnt sold on this date. So I would like to return the most recent hisotrical entry for the price.
Say if I query on the date 19-7-2011, I would like to return the entry on the 17th then the next 10 avalaible entries.
If however I query for the price of ABC on the 20th, I would want to return the price on the 20th and the next 10 prices after that...
What is the most efficient way to go about this either in SQL statement or using a stored proc.
I can think of just writing a stored proc which takes the date as a param and then querying for all rows where DATE >= QUERY-DATE ordering by the date and then selecting the 11 items (via limit). Then basically I need to see if that set contains the current date, if it does then return, otherwise I will need to return the 10 most recent entires out of those 11 and also do another query on the table to return the previous entry by getting the max date where date < QUERY-DATE. I am thinking there might be a better way, however I'm not an expert with SQL (clearly)...
Thanks!
This is for one specific code:
SELECT code, `date`, price
FROM code_prices
WHERE code = #inputCode
AND `date` >=
( SELECT MAX(`date`)
FROM code_prices
WHERE code = #inputCode
AND `date` <= #inputDate
)
ORDER BY `date`
LIMIT 11
For ABC and 19-7-2011, the above will you give the row for 17-7-2011 and the 10 subsequent rows (20-7-2011, 21-7-2011, etc)
I'm not entirely clear on what you want to achieve, but I'll have a go anyway. This searches for the ID of the row that contains a date less than or equal to your specified date. It then uses that ID to return all rows with an ID greater than or equal to that value. It assumes that you have a column other than the date column on which the rows can be ordered. This is because you said that the dates are non-linear - I assume that you must have some other way of ordering the rows.
SELECT id, code, dt, price
FROM code_prices
WHERE id >= (
SELECT id
FROM code_prices
WHERE dt <= '2011-07-24'
ORDER BY dt DESC
LIMIT 1 )
ORDER BY id
LIMIT 11;
Alternative with code condition - thanks to #ypercube for highlighting that ;-)
SELECT id, code, dt, price
FROM code_prices
WHERE code = 'ABC'
AND id >= (
SELECT id
FROM code_prices
WHERE dt <= '2011-07-23'
AND code = 'ABC'
ORDER BY dt DESC
LIMIT 1 )
ORDER BY id
LIMIT 11;