group by date, confirm, pending - mysql

im trying to build chart for users for each day with total confirmed user and total pending users for that each day and i need data like following:
date | confirmed | pending
2010-01-05 | 5 | 2
2010-01-06 | 10 | 3
following is the structure of the table:
user_id
username
confirm enum(0,1)
date date

SELECT Date, SUM(CASE Confirm WHEN 1 THEN 1 ELSE 0 END) Confirmed,
SUM(CASE Confirm WHEN 0 THEN 1 ELSE 0 END) Pending,
FROM Table
GROUP BY Date

Related

How do I aggregate from multiple rows

I have the below table:
Person_ID | Timestamp | Action
1 | 01-01-2020 00:01:00 | LOGGED ON
1 | 01-01-2020 00:02:00 | ON BREAK
1 | 01-01-2020 00:02:30 | OFF BREAK
1 | 01-01-2020 00:04:00 | LOGGED OFF
1 | 01-01-2020 00:04:30 | LOGGED ON
1 | 01-01-2020 00:05:30 | ON BREAK
1 | 01-01-2020 00:06:00 | OFF BREAK
1 | 01-01-2020 00:08:00 | LOGGED OFF
2 | 01-02-2020 00:04:00 | LOGGED ON
2 | 01-02-2020 00:10:00 | LOGGED OFF
My goal is to write an SQL view to get the below result:
Person_ID | LoggedInTime_hours | OnBreakTime_hours
1 | 6.5 | 1
2 | 6 | 0
For each Person_ID, calculate the difference in hours between each pair of occurrences of LOGGED IN/LOGGED OUT and ON BREAK/OFF BREAK respectively.
Thanks a lot for your expertise and help.
1st of all LoggedInTime_hours for PERSON_ID = 1 should be 5.5 hours not 6.5 hours.
Let us assume the table name is TEST.
Database : MySQL
SELECT
PERSON_ID,
IFNULL(SUM(CASE WHEN PREV_ACTIVE_IND - ACTIVE_IND > 0 THEN TIMESTAMPDIFF(SECOND, PREV_TIMESTAMP, TIMESTAMP)/3600 END),0) LoggedInTime_hours,
IFNULL(SUM(CASE WHEN PREV_ACTIVE_IND - ACTIVE_IND = 0 THEN TIMESTAMPDIFF(SECOND, PREV_TIMESTAMP, TIMESTAMP)/3600 END),0) OnBreakTime_hours
FROM
(SELECT
PERSON_ID,
PREV_ACTION,
ACTION,
CASE WHEN PREV_ACTION = 'LOGGED OFF' THEN 1
WHEN PREV_ACTION LIKE '%BREAK' THEN 2
WHEN PREV_ACTION IS NULL THEN NULL
ELSE 3
END AS PREV_ACTIVE_IND,
CASE WHEN ACTION = 'LOGGED OFF' THEN 1
WHEN ACTION LIKE '%BREAK' THEN 2
WHEN ACTION IS NULL THEN NULL
ELSE 3
END AS ACTIVE_IND,
PREV_TIMESTAMP,
TIMESTAMP
FROM
(SELECT PERSON_ID,
TIMESTAMP,
LAG(TIMESTAMP,1) OVER (PARTITION BY PERSON_ID) PREV_TIMESTAMP,
LAG(ACTION,1) OVER (PARTITION BY PERSON_ID) PREV_ACTION,
ACTION
FROM TEST) T) T2
GROUP BY PERSON_ID
Hope this query will help.
Try the following query using MySQL v8.0:
With CTE As
(
Select Person_ID, Action_,
TIME_TO_SEC(
TIMEDIFF(
Lead(Timestamp_) Over (Partition By Person_ID
Order By Case When Action_ In 'LOGGED ON','LOGGED OFF')
Then 1 Else 2 End,Timestamp_), Timestamp_
))/3600 As DIFF
From MyData
)
Select Person_ID,
Sum(Case When Action_='LOGGED ON' Then DIFF Else 0 End) As LoggedInTime_hours,
Sum(Case When Action_='ON BREAK' Then DIFF Else 0 End) As OnBreakTime_hours
From CTE
Group By Person_ID
See a demo from db-fiddle.
The Lead() function will find the next action date related to the current action i.e. (Logged In -> Logged Off), the actions are ordered according to their types; ('LOGGED ON','LOGGED OFF') ordered with 1, and ('ON BREAK','OFF BREAK') ordered with 2, then ordered by Timestamp of the action. Doing so, will ensure that each 'LOGGED ON' is followed by it's 'LOGGED OFF' action, and each 'ON BREAK' is followed by it's 'OFF BREAK' action.
Using TIMEDIFF we can find the difference between the actions times for each pair of actions ('LOGGED ON','LOGGED OFF'), ('ON BREAK','OFF BREAK'). Then the sum of these differences will be LoggedInTime_hours for logged in actions, and OnBreakTime_hours for on break actions.
The TIME_TO_SEC()/3600 is used to convert time differences to hours.

how to compare data between dates on multiply items at the same table

I have a table of items that I track inventory on daily basis (mysql)
| item_id | qty | created_at |
| ------- | -------| ---------- |
| 1 | 5 | 2021-04-08 |
| 1 | 30 | 2021-04-07 |
| 1 | 100 | 2021-04-06 |
| 2 | 100 | 2021-04-08 |
| 2 | 0 | 2021-04-07 |
| 2 | 0 | 2021-04-06 |
| 3 | 0 | 2021-04-08 |
| 3 | 50 | 2021-04-07 |
| 3 | 100 | 2021-04-06 |
I wonder how can I write an SQL query that analyze all items in the table and response some insights
for ex.
item_id = 1 ---> item is almost out of stock (5% limit point)
item_id = 2 ---> item just returned to stock (was 0 yesterday new we have 100)
item_id = 3 ---> item is out of stock today
also if there is another ideas for monitor the stock insights I'll be happy to know..
Thanks for all the helpers.
Consider running SQL jobs on regular time schedule.
Item is almost out of stock (5% limit)
Well five percent of what total (I assume it's not always 100 pcs). Create table with item_id and threshold value. If current stock is lower or equal to threshold value report it.
Item just returned to stock.
currentDay
is a function to return actual date like '2021/04/08' I am not familiar with mySql function/syntax
select item_id from myTable where qty > 0 and created_at = currentDay
and item_id IN (select item_id from myTable where qty = 0 and created_at = currentDay-1
Item is out of stock today
select item_id from myTable where qty = 0 and created_at = currentDay
//Edit after comments
1st comment: In case you want to see item that today is out of stock and yesterday it was not, tweak the provided query. Switch qty in conditions.
select item_id from myTable where qty = 0 and created_at = currentDay
and item_id IN (select item_id from myTable where qty > 0 and created_at = currentDay-1
2nd comment: Consider this. If your initial stock is 2pcs at day D, stock increase by 1000 at D+1 and stock increase by 70 at D+2. In case you take your stock qty from day D, your 5% is 0.1 pcs.
First of all that won't happen, so you should round up to nearest whole number (qty = 1) and second the stock qty warning may not be relevant. When your total stock is 1072 pcs your warning will trigger when qty <= 1 since it's based on stock qty from first day.
Just use lag() and some conditional logic:
select t.*,
(case when qty <= 5
then 'Almost out of stock'
when qty > 0 and lag(qty) over (partition by item_id order by created_at) = 0
then 'Just returned to stock'
when qty = 0 and lag(qty) over (partition by item_id order by created_at) > 0
then 'Out of stock today'
when qty = 0
then 'Still out of stock. How long will this go on?'
else 'Okay'
end) as status
from t

Finding total active hours by calculating difference between TimeDate records

I have a table to register users logs every one minute and other activities using DateTime for each user_id
This is a sample data of my table
id | user_id | log_datetime
------------------------------------------
1 | 1 | 2016-09-25 13:01:08
2 | 1 | 2016-09-25 13:04:08
3 | 1 | 2016-09-25 13:07:08
4 | 1 | 2016-09-25 13:10:08
5 | 2 | 2016-09-25 13:11:08
6 | 1 | 2016-09-25 13:13:08
7 | 2 | 2016-09-25 13:13:09
8 | 2 | 2016-09-25 13:14:10
I would like to calculate the total active time on the system
UPDATE: Expected Output
For Example user_id 1 his total available time should be 00:12:00
Since his hours and seconds are same so I'll just subtract last log from previous then previous from next previous and so on then I'll sum all subtracted values
this a simple for
Simply I want to loop through the data from last record to first record with in my range
this is a simple formula I hope that make my question clear
SUM((T< n > - T< n-1 >) + (T< n-1 > - T< n-2 >) ... + (T< n-x > - T< n-first >))
Since user_id 1 his hours and seconds are the same then I'll calculate the minutes only.
(13-10)+(10-7)+(7-4)+(4-1) = 12
user_id | total_hours
---------------------------------
1 | 00:12:00
2 | 00:03:02
I did this code
SET #start_date = '2016-09-25';
SET #start_time = '13:00:00';
SET #end_date = '2016-09-25';
SET #end_time = '13:15:00';
SELECT
`ul1`.`user_id`, SEC_TO_TIME(SUM(TIME_TO_SEC(`dl1`.`log_datetime`))) AS total_hours
FROM
`users_logs` AS `ul1`
JOIN `users_logs` AS `ul2`
ON `ul1`.`id` = `ul2`.`id`
WHERE
`ul1`.`log_datetime` >= CONCAT(#start_date, ' ', #start_time)
AND
`ul2`.`log_datetime` <= CONCAT(#end_date, ' ', #end_time)
GROUP BY `ul1`.`user_id`
But this code Sum all Time not getting the difference. This is the output of the code
user_id | total_hours
---------------------------------
1 | 65:35:40
2 | 39:38:25
How can I calculate the Sum of all difference datetime, then I want to display his active hours every 12 hours (00:00:00 - 11:59:59) and (12:00:00 - 23:59:59) with in selected DateTime Period at the beginning of the code
So the output would look like this (just an dummy example not from given data)
user_id | total_hours | 00_12_am | 12_00_pm |
-------------------------------------------------------
1 | 10:10:40 | 02:05:20 | 08:05:20 |
2 | 04:10:20 | 01:05:10 | 03:05:30 |
Thank you
So you log every minute and if a user is available there is a log entry.
Then count the logs per user, so you have the number of total minutes.
select user_id, count(*) as total_minutes
from user_logs
group by user_id;
If you want them displayed as time use sec_to_time:
select user_id, sec_to_time(count(*) * 60) as total_hours
from user_logs
group by user_id;
As to conditional aggregation:
select
user_id,
count(*) as total_minutes,
count(case when hour(log_datetime) < 12 then 1 end) as total_minutes_am,
count(case when hour(log_datetime) >= 12 then 1 end) as total_minutes_pm
from user_logs
group by user_id;
UPDATE: In order to count each minute just once count distinct minutes, i.e. DATE_FORMAT(log_datetime, '%Y-%m-%d %H:%i'). This can be done with COUNT(DISTINCT ...) or with a subquery getting distinct values.
The complete query:
select
user_id,
count(*) as total_minutes,
count(case when log_hour < 12 then 1 end) as total_minutes_am,
count(case when log_hour >= 12 then 1 end) as total_minutes_pm
from
(
select distinct
user_id,
date_format(log_datetime, '%y-%m-%d %h:%i') as log_moment,
hour(log_datetime) as log_hour
from.user_logs
) log
group by user_id;

How to put empty set in inner join

I am a complete beginner in MySql and I wanted you to help me. I want a DTR User Interface where there is time in and time out. So I have a fields like -id_biometrics,empno,datecreated,time_created,status,device the problem is if the employee forgot to time in or time out, I want to put the time in or time out to "NULL" here is what I coded.
SELECT start_log.empno AS "Employee Number", start_log.date_created, start_log.time_created AS "Time In", end_log.time_created AS "Time Out"
FROM biometrics AS start_log
INNER JOIN biometrics AS end_log ON start_log.empno = end_log.empno
WHERE start_log.status =0
AND end_log.status =1
AND start_log.empno =2
GROUP BY start_log.date_created, start_log.empno
And what my output here if he completes his time in and time out for the day is.
Employee Number|date_created |Time_in | Time_Out
2 | 2013-07-15 | 11:08:07 | 15:00:00
And if he/she forgots to Time Out or time in it shows MySQL returned an empty result set (i.e. zero rows). ( Query took 0.0016 sec )
What I wanted is
Employee Number | date_created |Time_in | Time_Out
3 | 2013-07-15 | 11:50:00 | Null
Please help me with this. I needed it badly thanks.
Are you looking for this?
SELECT empno, date_created,
MIN(CASE WHEN status = 0 THEN time_created END) time_in,
MIN(CASE WHEN status = 1 THEN time_created END) time_out
FROM biometrics
GROUP BY empno, date_created
Sample output:
+-------+--------------+----------+----------+
| empno | date_created | time_in | time_out |
+-------+--------------+----------+----------+
| 2 | 2013-07-15 | 11:08:07 | 15:00:00 |
| 3 | 2013-07-15 | 11:50:00 | NULL |
| 4 | 2013-07-15 | NULL | 16:00:00 |
+-------+--------------+----------+----------+
Here is SQLFiddle demo
UPDATE If you may have multiple in or out records and you always want to fetch first in and last out then just use MAX() aggregate for time_out
SELECT empno, date_created,
MIN(CASE WHEN status = 0 THEN time_created END) time_in,
MAX(CASE WHEN status = 1 THEN time_created END) time_out
FROM biometrics
GROUP BY empno, date_created
Here is SQLFiddle demo

Weekly report behalf of specific date field

I am using this query for weekly reporting but can not found a way like this
week_number | week_startdate | organization_1 | organization_2
---------------------------------------------------------------
1 | 2013-01--05 |count(date) like 4,24,etc_ | count(date) like 4,24,etc_
SQL:
SELECT WEEK(signed_date) AS week_name, signed_date AS Week_Starting,
YEAR(signed_date), WEEK(signed_date), COUNT(*)
FROM business
WHERE YEAR(signed_date) = YEAR(CURDATE())
GROUP BY CONCAT(YEAR(signed_date), '/', WEEK(signed_date))
ORDER BY YEAR(signed_date), WEEK(signed_date
SAMPLE DATA:
signed_date | organization_id
01-01-2013 | 1
02-01-2013 | 1
03-01-2013 | 2
In 1 week organization_1 have 2 signed & organization_2 has 1 signed.
You should use case within count or sum:
SELECT WEEK(signed_date) AS week_name, signed_date AS Week_Starting,
YEAR(signed_date), WEEK(signed_date),
SUM(CASE WHEN organization_id=1 THEN 1 ELSE 0 END) as organization_1,
SUM(CASE WHEN organization_id=2 THEN 1 ELSE 0 END) as organization_2
FROM business
WHERE YEAR(signed_date) = YEAR(CURDATE())
GROUP BY CONCAT(YEAR(signed_date), '/', WEEK(signed_date))
ORDER BY YEAR(signed_date), WEEK(signed_date);
http://sqlfiddle.com/#!2/587ad/3