I have a table where I store parsed server logs:
mysql> SELECT id,date,message_type FROM log_entry LIMIT 10 ;
+----+---------------------+--------------+
| id | date | message_type |
+----+---------------------+--------------+
| 1 | 2015-01-08 18:13:15 | 2 |
| 2 | 2015-01-08 18:13:14 | 1 |
| 3 | 2015-01-08 18:13:12 | 1 |
| 4 | 2015-01-08 18:13:11 | 1 |
| 5 | 2015-01-08 18:13:11 | 1 |
| 6 | 2015-01-08 18:13:11 | 1 |
| 7 | 2015-01-08 18:13:10 | 1 |
| 8 | 2015-01-08 18:13:08 | 1 |
| 9 | 2015-01-08 18:13:07 | 1 |
| 10 | 2015-01-08 18:13:06 | 512 |
+----+---------------------+--------------+
Each log is classified by its message_type. I can also group them by hour:
mysql> select DAY(date) as day, HOUR(date) as hour, message_type, count(message_type) FROM log_entry WHERE date >= CURDATE() - INTERVAL 2 MONTH AND message_type BETWEEN 1 AND 4 GROUP BY day,hour,message_type ORDER BY date ASC LIMIT 3;
+------+------+--------------+---------------------+
| day | hour | message_type | count(message_type) |
+------+------+--------------+---------------------+
| 8 | 18 | 1 | 177 |
| 8 | 18 | 2 | 61 |
| 8 | 18 | 4 | 14 |
+------+------+--------------+---------------------+
In this example, on the 8th day and the 18th hour of a certain date, I have 177 entries with a message_type of 1, 61 with type 2 and 14 with type 4.
I would like to get the following calculation for every hour:
type(1) - type(2) - type(4)
Which in this case would return
+------+------+--------------+---------------------+
| day | hour | result |
+------+------+--------------+---------------------+
| 8 | 18 | 102 |
+------+------+--------------+---------------------+
I'm doing this is because I want to create a chart showing hourly activity on a server I'm running. A type 1 entry means someone connected, a type 2 means there was a graceful disconnect and a type 4 means there was a timeout.
Is this a feasible thing to do in the database or should I do this on the application layer?
You can use a SUM() function and CASE statement to count each message_type and do the math.
SELECT DAY(date) as day, HOUR(date) as hour,
SUM(CASE WHEN message_type = 1 THEN 1 ELSE 0 END) -
SUM(CASE WHEN message_type = 2 THEN 1 ELSE 0 END) -
SUM(CASE WHEN message_type = 4 THEN 1 ELSE 0 END) as result
FROM log_entry
WHERE date >= CURDATE() - INTERVAL 2 MONTH
AND message_type BETWEEN 1 AND 4
GROUP BY day,hour;
Related
I have two table first user table is user's data second table is user_volume table is user cost volume I want one sql query and get user and get monthly sum of cost what is SQL Query?
user_volume
id | user_id | volume | created_at
1 | 1 | 66.00 | 2018-03-03 15:36:45
2 | 1 | 77.00 | 2018-03-03 15:36:21
3 | 1 | 88.00 | 2018-03-03 15:36:11
4 | 2 | 99.00 | 2018-03-03 19:36:15
5 | 2 | 65.05 | 2018-04-04 21:30:07
6 | 2 | 99.00 | 2018-04-04 19:36:15
7 | 2 | 65.05 | 2018-04-04 21:30:07
8 | 1 | 22.00 | 2018-04-04 15:36:45
9 | 1 | 44.00 | 2018-04-04 15:36:21
10 | 1 | 33.00 | 2018-04-04 15:36:11
11 | 2 | 13.00 | 2018-04-04 15:36:45
12 | 2 | 224.00 | 2018-04-04 15:36:21
13 | 2 | 651.00 | 2018-04-04 15:36:11
user
id | name | surname
1 | X | Y
result
user_id | date1(03-2018) | date2(04-2018)
1 | (231) | (99)
2 | (99) | (888)
You seem to want conditional aggregation:
select uv.id as user_id,
sum(case when created_at >= '2018-03-01' and created_at < '2018-04-1'
then volume else 0
end) as volume_month1,
sum(case when created_at >= '2018-04-01' and created_at < '2018-05-1'
then volume else 0
end) as volume_month2
from user_volume uv
group by uv.id
I need to get a result that will display the total count of transaction type and group it with 15 mins interval based on the "Intime" column.
Sample Dataset -- Database Name is transactions
--------------------------------------
| InTime | TransactionType | PaidAmt |
--------------------------------------
| 09:03 | PickUp | 10.02 |
| 09:09 | Delivery | 5.05 |
| 09:14 | Delivery | 3.99 |
| 09:15 | Delivery | 1.99 |
| 09:20 | PickUp | 10.35 |
| 09:23 | PickUp | 23.01 |
| 09:33 | PickUp | 10.06 |
| 09:44 | Delivery | 1.99 |
---------------------------------------
This is the desired result.
-------------------------------------------------------------------------------
| TimeFrame | NumberofPickUp | TotalPickUp | NumberofDelivery | TotalDelivery |
-------------------------------------------------------------------------------
| 09:00 | 1 | 10.02 | 2 | 9.04 |
| 09:15 | 2 | 33.36 | 1 | 1.99 |
| 09:30 | 1 | 10.06 | 1 | 1.99 |
-------------------------------------------------------------------------------
You can do this by rounding down all your time values to the next lower 15 minute boundary, which you can do with
SEC_TO_TIME(FLOOR(TIME_TO_SEC(InTime) / 900) * 900)
You can then use this value to GROUP BY, and conditional aggregation to get the totals you need:
SELECT SEC_TO_TIME(FLOOR(TIME_TO_SEC(InTime) / 900) * 900) AS TimeFrame,
SUM(TransactionType = 'Pickup') AS `Number of Pickup`,
ROUND(SUM(CASE WHEN TransactionType = 'Pickup' THEN PaidAmt ELSE 0 END), 2) AS `Total Pickup`,
SUM(TransactionType = 'Delivery') AS `Number of Delivery`,
ROUND(SUM(CASE WHEN TransactionType = 'Delivery' THEN PaidAmt ELSE 0 END), 2) AS `Total Delivery`
FROM transactions
GROUP BY TimeFrame
Output:
TimeFrame Number of Pickup Total Pickup Number of Delivery Total Delivery
09:00:00 1 10.02 2 9.04
09:15:00 2 33.36 1 1.99
09:30:00 1 10.06 1 1.99
Demo on dbfiddle
If there are timeframes of interest that are not present in your table, you can most easily generate the appropriate 0 values in your application code.
I have user attendance CLOCK IN data like this.
id | userID | created_at
1 | 1 | 2018-06-27 00:15:00
2 | 1 | 2018-06-27 01:43:55
3 | 1 | 2018-06-27 02:43:55
4 | 2 | 2018-06-27 00:15:00
5 | 2 | 2018-06-27 02:43:55
6 | 2 | 2018-06-27 03:43:55
7 | 1 | 2018-06-28 00:55:00
8 | 1 | 2018-06-28 01:43:55
9 | 1 | 2018-06-28 02:43:55
10 | 2 | 2018-06-28 00:00:00
11 | 2 | 2018-06-28 02:43:55
12 | 2 | 2018-06-28 03:43:55
I want a list of dates where user was late to clock in.
Assume company work time is 00:00:00 and
How can I get results like this :
id | userID | created_at
1 | 1 | 2018-06-27 00:15:00
4 | 2 | 2018-06-27 00:15:00
7 | 1 | 2018-06-28 00:55:00
Appreciate any help from you guys.Thanks 🙏🏻
You could try conditionally aggregating by user and date, and then checking to see whether an exact midnight clock in occurred (or did not occur):
SELECT
userID,
MIN(created_at) AS created_at
FROM yourTable
GROUP BY
userID,
DATE(created_at)
HAVING
SUM(CASE WHEN DATE_FORMAT(created_at, '%H:%i:%s') = '00:00:00' THEN 1 ELSE 0 END) = 0;
Demo
I am running this query and getting the data like attached below
mysql> ( SELECT date_range AS 'Time Elapsed', COUNT(*) AS 'Conversions' FROM `data` GROUP BY date_sort_sno, `date_range` ORDER BY date_sort_sno )
-> UNION ALL
-> ( SELECT date_range AS 'Time Elapsed', COUNT(*) AS 'A_Conversio' FROM `data` GROUP BY date_sort_sno, `date_range` WHERE name = 'Alpha' ORDER BY date_sort_sno );
OUTPUT
+------------------------------+-------------+
| Time Elapsed | Conversions |
+------------------------------+-------------+
| Less than equal to 5 minutes | 1391 |
| 5 to 30 minutes | 9108 |
| 30 to 60 minutes | 2233 |
| 1 hour to 3 hours | 2280 |
| 3 hours to 24 hours | 4585 |
| 1 to 3 days | 4143 |
| 3 to 6 days | 155 |
| more than 6 days | 80 |
| Less than equal to 5 minutes | 1391 |
| 5 to 30 minutes | 9108 |
| 30 to 60 minutes | 2233 |
| 1 hour to 3 hours | 2280 |
| 3 hours to 24 hours | 4585 |
| 1 to 3 days | 4143 |
| 3 to 6 days | 155 |
| more than 6 days | 80 |
+------------------------------+-------------+
Problem Statement:
I want to merge the data on the basis of Time Elapsed like
+------------------------------+-------------+-------------+
| Time Elapsed | Conversions | A_Conversio |
+------------------------------+-------------+-------------+
| Less than equal to 5 minutes | 1391 | 1231 |
| 5 to 30 minutes | 1391 | 4455 |
| 30 to 60 minutes | 2233 | 3333 |
| 1 hour to 3 hours | 2280 | 4343 |
| 3 hours to 24 hours | 4585 | 2234 |
| 1 to 3 days | 4143 | 2344 |
| 3 to 6 days | 155 | 455 |
| more than 6 days | 80 | 11 |
+------------------------------+-------------+-------------+
Instead of two separate queries, you could have one query with two columns - a plain old count(*) to count all the records and a count function applied to a case expression to count only the conversions where the name is 'Alpha':
SELECT date_range AS 'Time Elapsed',
COUNT(*) AS 'Conversions',
COUNT(CASE name WHEN 'Alpha' THEN 1 END) AS 'A_Conversio'
FROM `data`
GROUP BY date_sort_sno, `date_range`
ORDER BY date_sort_sno
I am not sure this data structure able to do the result I want.
http://sqlfiddle.com/#!9/84939
This is the data, please ignore the duration column.
+----+---------------------+---------------------+---------------------+----------+--------+------+
| id | created_date | start_date | end_date | duration | status | type |
+----+---------------------+---------------------+---------------------+----------+--------+------+
| 1 | 2016-04-05 15:23:29 | 2016-08-15 10:21:53 | 2016-08-19 00:00:00 | 30 | 1 | 2 |
| 2 | 2016-04-06 15:23:29 | 2016-08-15 10:21:53 | 2016-08-19 00:00:00 | 30 | 1 | 1 |
| 3 | 2016-04-06 15:23:29 | 2016-08-15 10:21:53 | 2016-08-19 00:00:00 | 30 | 1 | 3 |
| 4 | 2016-04-06 15:23:29 | 2016-08-17 10:21:53 | 2016-08-19 00:00:00 | 30 | 1 | 1 |
| 5 | 2016-04-06 15:23:29 | 2016-08-17 09:21:53 | 2016-08-19 00:00:00 | 30 | 1 | 1 |
| 6 | 2016-04-06 15:23:29 | 2016-08-01 09:21:53 | 2016-08-31 00:00:00 | 30 | 1 | 1 |
| 7 | 2016-04-06 15:23:29 | 2016-08-01 09:21:53 | 2016-08-31 00:00:00 | 30 | 0 | 1 |
| 8 | 2016-04-06 15:23:29 | 2016-08-15 09:21:53 | 2016-08-16 00:00:00 | 30 | 1 | 2 |
| 9 | 2016-04-06 15:23:29 | 2016-08-16 09:21:53 | 2016-08-17 00:00:00 | 30 | 1 | 3 |
| 10 | 2016-04-06 15:23:29 | 2016-08-19 09:21:53 | 2016-08-20 00:00:00 | 30 | 1 | 2 |
+----+---------------------+---------------------+---------------------+----------+--------+------+
I want to filter the report from 2016-08-15 until 2016-08-19. for 2015-08-19 even 00:00:00, I am not sure consider count or not. But for my example. I just count it because it is in the range.
This is the summary done by me manually:-
(type-2)15,16,17,18,19
(type-1)15,16,17,18,19
(type-3)15,16,17,18,19
(type-1)17,18,19
(type-1)17,18,19
(type-1)15,16,17,18,19
(type-1)15,16,17,18,19
(type-2)15,16
(type-3)16,17
(type-2)19,20
This is the result I would like to generate in sql return data.
+------------+--------+-----------+-----------+-----------+
| date | ct_all | ct_type_1 | ct_type_2 | ct_type_3 |
+------------+--------+-----------+-----------+-----------+
| 2016-08-15 | 6 | 3 | 2 | 1 |
| 2016-08-16 | 7 | 3 | 2 | 2 |
| 2016-08-17 | 8 | 5 | 1 | 2 |
| 2016-08-18 | 7 | 5 | 1 | 1 |
| 2016-08-19 | 8 | 5 | 2 | 1 |
+------------+--------+-----------+-----------+-----------+
ct_all = count all
ct_type_1 = count total for type 1
As long as the type fall into start_date and end_date then it will count.
Normally we done search date is base on one column type, e.g created_date. and I can use between >= and <= to find the range. But this one got start and end date. Not sure can be accomplished or not.
You have three different things going on here.
an enumeration of days.
a DATETIME range filter.
a so-called pivot, pivoting rows by type into columns.
It's helpful to take these one at a time.
First, I guess you have five days you wish to filter, [15-Aug-2016 - 19-Aug-2016] inclusive. You want to make a list of all those days. This little query will do that. (http://sqlfiddle.com/#!9/84939/21/0)
SELECT CONVERT('2016-08-15' + INTERVAL seq DAY, DATETIME) AS CURDATE
FROM (SELECT 0 AS SEQ UNION ALL SELECT 1 UNION ALL SELECT 2
UNION ALL SELECT 3 UNION ALL SELECT 4
) seq_0_to_4
(Notice something: The MariaDB fork of MySQL has sequence tables like seq_0_to_4 built in so you don't have to do all this UNION ALL stuff.)
Second, you want to get a list of the type values occurring on each day. You can get that to happen with a LEFT JOIN, like so (http://sqlfiddle.com/#!9/84939/26/0).
SELECT seq.curdate, record.type
FROM (
SELECT CONVERT('2016-08-15' + INTERVAL seq DAY, DATETIME) AS CURDATE
FROM (SELECT 0 AS SEQ UNION ALL SELECT 1 UNION ALL SELECT 2
UNION ALL SELECT 3 UNION ALL SELECT 4
) seq_0_to_4
) seq
LEFT JOIN record ON seq.curdate >= DATE(record.start_date)
AND seq.curdate <= DATE(record.end_date)
This gives you a list of curdate and type values.
The ON condition of that join chooses record rows that start on or before each date, and end anytime on each date.
Finally, you need to do a pivot operation to summarize the counts of type values. That looks something like this. (http://sqlfiddle.com/#!9/84939/28/0)
SELECT curdate,
COUNT(type) ct_all,
SUM(CASE WHEN type = 1 THEN 1 ELSE 0 END) ct_1,
SUM(CASE WHEN type = 2 THEN 1 ELSE 0 END) ct_2,
SUM(CASE WHEN type = 3 THEN 1 ELSE 0 END) ct_3
FROM (the above query) d
GROUP BY curdate
ORDER BY curdate
This is a case where the structured part of Structured Query Language is necessary.