Currently, I have this table: date_time_records where all of the time in and out of employees are being saved.
As you can see all of the data of time in and out are being stored for each row.
and these data can be identified if it is time in or out using state field
Time in = C/In
Time Out = C/Out
Expected Output
Now I'm trying to do a query something like this
Where you can see the same employee record but different day
and you can notice that the time in and out is being arranged.
Here's my code
SELECT
a.id,
a.ACNo,
a.name,
a.email,
(SELECT MAX(datetime) FROM date_time_records WHERE id = a.id AND state = "C/In") as time_in,
(SELECT MIN(datetime) FROM date_time_records WHERE id = a.id AND state = "C/Out") as time_out,
FROM `date_time_records` as a GROUP BY datetime ORDER BY `created_at` ASC
Please disregard the created_at
I'm using datetime since the system is capable to do a bulk upload of time in and out. of past data.
You could do something like this:
SELECT ACNo, Name,
SUBSTRING_INDEX(GROUP_CONCAT(CASE WHEN state='C/In' THEN DATETIME END ORDER BY DATETIME ASC),',',1) AS time_in,
SUBSTRING_INDEX(GROUP_CONCAT(CASE WHEN state='C/Out' THEN DATETIME END ORDER BY DATETIME ASC),',',-1) AS time_out,
DATE(DATETIME) AS recDate
FROM date_time_records
GROUP BY ACNo, Name,recDate
ORDER BY ACNo;
Using GROUP_CONCAT then SUBSTRING_INDEX to get the first & last value.
Fiddle here: https://www.db-fiddle.com/f/bfkoKK13kcE8NYVzo71Zi3/3
Use conditional aggregation:
SELECT dtr.id, dtr.ACNo, dtr.name, dtr.email,
MAX(CASE WHEN dtr.stat = 'C/IN' THEN dtr.datetime END) as time_in,
MIN(CASE WHEN dtr.stat = 'C/OUT' THEN dtr.datetime END) as time_out
FROM date_time_records dtr
GROUP BY dtr.id, dtr.ACNo, dtr.name, dtr.email
ORDER BY MIN(created_at) ASC
Could you just log a user's time in/time out separately from the date? That'd make the min/max query for time in/time out on a daily basis a lot simpler.
Related
I have a data set that looks like this:
my mission is to Write a logical condition in MySQL based on the check-in and check-out dates to retrieve all stays that
include (the night of) March 23rd. I tried this :
check_in<="23/03/2019" and check_out>"23/03/2019"
but I found out that stayed with check-in = ‘2019-03-21’ and check-out =
‘2019-03-25’ wasn't retrieved even though it includes the 23r. I wonder what is the problem and how could I fix it? thank you :)
You need to join it with itself to be able to search on both terms. Assuming your table is called stays:
SELECT a.stay_id,a.date check_in,b.date check_out FROM stays a JOIN stays b ON a.stay_id=b.stay_id AND a.event_type='check-in' AND b.event_type='check-out' WHERE a.date<="2019-03-23" AND b.date>"2019-03-23";
Use a subquery that groups by stay_id and checks your requirement in the HAVING clause:
select *
from tablename
where stay_id in (
select stay_id from tablename
group by stay_id
having '2019-03-23' between
max(case when event_type = 'check-in' then date end) and max(case when event_type = 'check-out' then date end)
)
or since a check-out date is (I assume) later than or equal to a check-in date:
select *
from tablename
where stay_id in (
select stay_id from tablename
group by stay_id
having '2019-03-23' between min(date) and max(date)
)
Or if you want 1 row for each stay_id:
select stay_id, min(date) check_in_date, max(date) check_out_date
from tablename
group by stay_id
having '2019-03-23' between min(date) and max(date)
Assume everyone checked out:
select stay_id
from tbl
where event_type = 'check-in' and date <= '2019-03-23'
and stay_id in
(select stay_id
from tbl
where event_type = 'check-out' and date > '2019-03-23')
I can edit later to create a logic to include people not checked out yet
SO i have a task and i need to group my results by Date and by Provider_name but currently my code is listing out multiple dates and Providers. (need to have one provider per day (25 days in all) so my table shows how many messages the provider got that day and how much did they earn)
This needs to be my result. Result table
But this is what i'm currently getting
This is my code currently
SELECT date_format( time, '%Y-%m-%d' ) AS Date, provider_name, COUNT( message_id ) AS Messages_count, SUM( price ) AS Total_price
FROM mobile_log_messages_sms
INNER JOIN service_instances ON service_instances.service_instance_id = mobile_log_messages_sms.service_instance_id
INNER JOIN mobile_providers ON mobile_providers.network_code = mobile_log_messages_sms.network_code
WHERE time
BETWEEN '2017-02-26 00:00:00'
AND time
AND '2017-03-22 00:00:00'
AND price IS NOT NULL
AND price <> ''
AND service IS NOT NULL
AND service <> ''
AND enabled IS NOT NULL
AND enabled >=1
GROUP BY provider_name, time
ORDER BY time DESC
Can you tell me where i've messed up, i really can't figure out the answer.
Try like this:
....
GROUP BY provider_name, date_format( time, '%Y-%m-%d' )
ORDER BY time DESC
You are grouping time which will group the result by time including hour, minute and second so on ... that is why you getting different count from same day. Try grouping by day instead.
time column is datetime. So its grouped by date and time both rather than just date.
Change GROUP BY statement to
GROUP BY provider_name, date_format( time, '%Y-%m-%d' )
I have a lookup table that relates dates and people associated with those dates:
id, user_id,date
1,1,2014-11-01
2,2,2014-11-01
3,1,2014-11-02
4,3,2014-11-02
5,1,2014-11-03
I can group these by date(day):
SELECT DATE_FORMAT(
MIN(date),
'%Y/%m/%d 00:00:00 GMT-0'
) AS date,
COUNT(*) as count
FROM user_x_date
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) / 43200)
But, how can get the number of unique users, that have now shown up previously? For instance this would be a valid result:
unique, non-unique, date
2,0,2014-11-01
1,1,2014-11-02
0,1,2014-11-03
Is this possibly without having to rely on a scripting language to keep track of this data?
I think this query will do what you want, at least it seems to work for your limited sample data.
The idea is to use a correlated sub-query to check if the user_id has occurred on a date before the date of the current row and then do some basic arithmetic to determine number of unique/non-unique users for each date.
Please give it a try.
select
sum(u) - sum(n) as "unique",
sum(n) as "non-unique",
date
from (
select
date,
count(user_id) u,
case when exists (
select 1
from Table1 i
where i.user_id = o.user_id
and i.date < o.date
) then 1 else 0
end n
from Table1 o
group by date, user_id
) q
group by date
order by date;
Sample SQL Fiddle
I didn't include the id column in the sample fiddle as it's not needed (or used) to produce the result and won't change anything.
This is the relevant question: "But, how can get the number of unique users, that have now shown up previously?"
Calculate the first time a person shows up, and then use that for the aggregation:
SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date;
I would then use this as a subquery for another aggregation:
SELECT v.date, v.NumVisits, COALESCE(fv.FirstVisit, 0) as NumFirstVisit
FROM (SELECT date, count(*) as NumVisits
FROM user_x_date
GROUP BY date
) v LEFT JOIN
(SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date
) fv
ON v.date = fv.date;
I have a TABLE with Columns: USER_ID,TIMESTAMP and ACTION
Every row tells me which user did what action at a certain time-stamp.
Example:
Alice starts the application at 2014-06-12 16:37:46
Alice stops the application at 2014-06-12 17:48:55
I want a list of users with the time difference between the first row in which they start the application and the last row in which they close it.
Here is how I'm trying to do it:
SELECT USER_ID,DATEDIFF(
(SELECT timestamp FROM MOBILE_LOG WHERE ACTION="START_APP" AND USER_ID="Alice" order by TIMESTAMP LIMIT 1),
(SELECT timestamp FROM MOBILE_LOG WHERE ACTION ="CLOSE_APP" AND USER_ID="Alice" order by TIMESTAMP LIMIT 1)
) AS Duration FROM MOBILE_LOG AS t WHERE USER_ID="Alice";
I ask for the DATEDIFF between two SELECT queries, but I just get a list of Alice`s with -2 as Duration.
Am i on the right track?
I think you should group this table by USER_ID and find minimum date of "START_APP" and maximum of "CLOSE_APP" for each user. Also you should use in DATEDIFF the CLOSE_APP time first and then START_APP time in this case you will get positive value result
SELECT USER_ID,
DATEDIFF(MAX(CASE WHEN ACTION="CLOSE_APP" THEN timestamp END),
MIN(CASE WHEN ACTION="START_APP" THEN timestamp END)
) AS Duration
FROM MOBILE_LOG AS t
GROUP BY USER_ID
SQLFiddle demo
SELECT user_id, start_time, close_time, DATEDIFF(close_time, start_time) duration
FROM
(SELECT MIN(timestamp) start_time, user_id FROM MOBILE_LOG WHERE action="START_APP" GROUP BY user_id) start_action
JOIN
(SELECT MAX(timestamp) close_time, user_id FROM MOBILE_LOG WHERE ACTION ="CLOSE_APP" GROUP BY user_id) close_action
USING (user_id)
WHERE USER_ID="Alice";
You make two "tables" with the earliest time for start for each user, and the latest time for close for each user. Then join them so that the actions of the same user are together.
Now that you have everything setup you can easily subtract between them.
You have the int value because you use the function DATEDIFF, it shows you the number of days between two dates, if you want to have the number of hours and minutes and seconds between dates you have to use TIMEDIFF
Try this:
select t1.USER_ID, TIMEDIFF(t2.timestamp, t1.timestamp)
from MOBILE_LOG t1, MOBILE_LOG t2
where (t1.action,t1.timestamp) in (select action, max(timestamp) from MOBILE_LOG t where t.ACTION = "START_APP" group by USER_ID)
and (t1.action,t1.timestamp) in (select action, max(timestamp), max(id) from MOBILE_LOG t where t.ACTION = "CLOSE_APP" group by USER_ID)
and t1.USER_ID = t2.USER_ID
It will show you difference between two latest dates (startdate,enddate) for all user.
P.S: Sorry, I wrote it without any databases, and may be there are some mistakes. If you have problems with (t1.action,t1.timestamp) in (select...) split it on two: where t1.action in (select ...) and t1.timestamp in (select ...)
Im currently trying to run a SQL query to export data between a certain date, but it runs the query fine, just not the date selection and i can't figure out what's wrong.
SELECT
title AS Order_No,
FROM_UNIXTIME(entry_date, '%d-%m-%Y') AS Date,
status AS Status,
field_id_59 AS Transaction_ID,
field_id_32 AS Customer_Name,
field_id_26 AS Sub_Total,
field_id_28 AS VAT,
field_id_31 AS Discount,
field_id_27 AS Shipping_Cost,
(field_id_26+field_id_28+field_id_27-field_id_31) AS Total
FROM
exp_channel_data AS d NATURAL JOIN
exp_channel_titles AS t
WHERE
t.channel_id = 5 AND FROM_UNIXTIME(entry_date, '%d-%m-%Y') BETWEEN '01-05-2012' AND '31-05-2012' AND status = 'Shipped'
ORDER BY
entry_date DESC
As explained in the manual, date literals should be in YYYY-MM-DD format. Also, bearing in mind the point made by #ypercube in his answer, you want:
WHERE t.channel_id = 5
AND entry_date >= UNIX_TIMESTAMP('2012-05-01')
AND entry_date < UNIX_TIMESTAMP('2012-06-01')
AND status = 'Shipped'
Besides the date format there is another issue. To effectively use any index on entry_date, you should not apply functions to that column when you use it conditions in WHERE, GROUP BY or HAVING clauses (you can use the formatting in SELECT list, if you need a different than the default format to be shown). An effective way to write that part of the query would be:
( entry_date >= '2012-05-01'
AND entry_date < '2012-06-01'
)
It works with DATE, DATETIME and TIMESTAMP columns.