Calculate timediff but exclude weekend - mysql

How to calculate total hours between now and any date but to exclude weekdays?
I'm trying on this way:
select id, creationTime,
time_format(timediff(now(), creationTime), '%H:%m:%s') AS totalspenttime
from tblrezgo where DAYOFWEEK(creationTime) NOT IN (1,7)
This query should remove saturday and sundays from calculation but it seems that includes also those two days.
By running query:
select id, creationTime, DAYOFWEEK(creationTime) FROM tblrezgo
Output is:
+-------------+---------------------+------------+
| ID | creationTime | DAYOFWEEK |
+-------------+---------------------+------------+
| 1 | 2015-10-23 17:12:05 | 6 |
+-------------+---------------------+------------+
| 2 | 2015-10-24 10:23:11 | 7 |
+-------------+---------------------+------------+
| 3 | 2015-10-24 11:51:04 | 7 |
+-------------+---------------------+------------+
| 4 | 2015-10-26 14:30:28 | 2 |
+-------------+---------------------+------------+
| 5 | 2015-10-26 08:24:59 | 2 |
+-------------+---------------------+------------+
| 6 | 2015-10-26 17:29:03 | 2 |
+-------------+---------------------+------------+
| 7 | 2015-10-27 08:16:45 | 3 |
+-------------+---------------------+------------+
If i run my query then totalspenttime for ID = 1 is about 86 hour which is not correct. I've checked and it should be about 41 hours 'til now (if we execlude two days of weekend).

Related

Converting lump sums to transactions

I have a database that tracks the size of claims.
Each claim has fixed information that is stored in claim (such as claim_id and date_reported_to_insurer).
Each month, I get a report which is added to the table claim_month. This includes fields such as claim_id, month_id [101 is 31/01/2018, 102 is 28/02/2018, etc] and paid_to_date.
Since most claims don't change from month to month, I only add a record for claim_month when the figure has changed since last month. As such, a claim may have a June report and an August report, but not a July report. This would be because the amount paid to date increased in June and August, but not July.
The problem that I have now is that I want to be able to check the amount paid each month.
Consider the following example data:
+----------------+----------+----------------+--------------+
| claim_month_id | claim_id | month_id | paid_to_date |
+----------------+----------+----------------+--------------+
| 1 | 1 | 6 | 1000 |
+----------------+----------+----------------+--------------+
| 5 | 1 | 7 | 1200 |
+----------------+----------+----------------+--------------+
| 7 | 2 | 6 | 500 |
+----------------+----------+----------------+--------------+
| 12 | 1 | 9 | 1400 |
+----------------+----------+----------------+--------------+
| 18 | 2 | 8 | 600 |
+----------------+----------+----------------+--------------+
If we assume that this is all of the information regarding claim 1 and 2, then that would suggest that they are both claims that occurred during June 2018. Their transactions should look like the following:
+----------------+----------+----------------+------------+
| claim_month_id | claim_id | month_id | paid_month |
+----------------+----------+----------------+------------+
| 1 | 1 | 6 | 1000 |
+----------------+----------+----------------+------------+
| 5 | 1 | 7 | 200 |
+----------------+----------+----------------+------------+
| 7 | 2 | 6 | 500 |
+----------------+----------+----------------+------------+
| 12 | 1 | 9 | 200 |
+----------------+----------+----------------+------------+
| 18 | 2 | 8 | 100 |
+----------------+----------+----------------+------------+
The algorithm I'm using for this is
SELECT claim_month_id,
month_id,
claim_id,
new.paid_to_date - old.paid_to_date AS paid_to_date_change,
FROM claim_month AS new
LEFT JOIN claim_month AS old
ON new.claim_id = old.claim_id
AND ( new.month_id > old.month_id
OR old.month_id IS NULL )
GROUP BY new.claim_month_id
HAVING old.month_id = Max(old.month_id)
However this has two issues:
It seems really inefficient at dealing with claims with multiple
records. I haven't run any benchmarking, but it's pretty obvious.
It doesn't show new claims. In the above example, it would only show lines 2, 3 and 5.
Where am I going wrong with my algorithm, and is there a better logic to use to do this?
Use LAG function to get the next paid_to_date of each claim_id, and use the current paid_to_date minus the next paid_to_date.
SELECT
claim_month_id,
claim_id,
month_id,
paid_to_date - LAG(paid_to_date, 1, 0) OVER (PARTITION BY claim_id ORDER BY month_id) AS paid_month
FROM claim
The output table is:
+----------------+----------+----------+------------+
| claim_month_id | claim_id | month_id | paid_month |
+----------------+----------+----------+------------+
| 1 | 1 | 6 | 1000 |
| 5 | 1 | 7 | 200 |
| 12 | 1 | 9 | 200 |
| 7 | 2 | 6 | 500 |
| 18 | 2 | 8 | 100 |
+----------------+----------+----------+------------+

mysql display each type in row and group by date range

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.

mysql select latest record only for record

I have a MySQL database with the following structure:
custodian | counta | countc | countc | total | date
-------------------------------------------------------
ed | 1 | 2 | 3 | 6 | 1/1/2016
ed | 2 | 3 | 5 | 10 | 1/2/2016
ed | 2 | 3 | 6 | 11 | 1/3/2016
ed | 1 | 3 | 5 | 9 | 1/4/2016
fred | 1 | 2 | 3 | 6 | 1/1/2016
fred | 2 | 3 | 5 | 10 | 1/2/2016
fred | 2 | 3 | 6 | 11 | 1/3/2016
fred | 1 | 3 | 5 | 9 | 1/4/2016
How do I return the latest record for a custodian? I've been playing around with this condition where date >= DATE_SUB(NOW(),INTERVAL 59 MINUTE) since the table is updated hourly, but if I update the script twice in an hour, I would return more than one result per custodian.
Any advice?
You need to combine ORDER BY and LIMIT:
SELECT *
FROM yourTableName
WHERE custodian = 123
ORDER BY `date` DESC
LIMIT 1
You could try this
SELECT * FROM tbl ORDER BY date DESC LIMIT 1
The most recent date will be the first record when ordered decendingly, and limiting the select to 1 means you get only the latest record.

MySQL select a row from a daterange excluding the year

I'm trying to create a MySQL query to select the daily price from a table that is between a date range from another. I only want to use 'starting-ending' months and days from the table "seasons" and I want to pass the year dynamically to the query.
This is my query: (I'm giving it the Year to exclude the one on the table)
SELECT a.season, b.base_price
FROM seasons a
JOIN pricebyseason b ON a.id=b.season_id
WHERE b.prop_id='6' AND '2015-11-29' BETWEEN DATE_FORMAT(a.starting,'2015-%m-%d') AND DATE_FORMAT(a.ending,'2016-%m-%d')
ORDER BY b.base_price DESC
It works but not with all dates.
These are the tables:
seasons (these are static date values)
+----+--------------+------------+------------+
| id | season | starting | ending |
+----+--------------+------------+------------+
| 1 | Peak Season | 2015-12-11 | 2016-01-09 |
| 2 | High Season | 2015-11-27 | 2016-04-15 |
| 3 | Mid Season | 2015-04-16 | 2015-09-01 |
| 4 | Low Season | 2015-09-02 | 2015-11-26 |
| 5 | Spring Break | 2015-03-05 | 2015-03-21 |
+----+--------------+------------+------------+
pricebyseason
+----+---------+-----------+------------+
| id | prop_id | season_id | base_price |
+----+---------+-----------+------------+
| 1 | 6 | 1 | 950 |
| 2 | 6 | 2 | 750 |
| 3 | 6 | 3 | 450 |
| 4 | 6 | 4 | 400 |
| 5 | 6 | 5 | 760 |
+----+---------+-----------+------------+
What I want to achive is query the dialy price between checkin, checkout selection
I create this sqlfiddle: http://sqlfiddle.com/#!9/4a6f4
This is a previuos query that is not working either:
SELECT a.base_price,b.season,b.starting,b.ending
FROM pricebyseason a JOIN seasons b ON a.season_id=b.id
WHERE a.prop_id='6' AND
(DATE_FORMAT(b.starting,'%m-%d') <= '12-27' OR DATE_FORMAT(b.starting,'2016-%m-%d') >= '2015-12-27')
AND
(DATE_FORMAT(b.ending,'%m-%d') >= '12-27' OR DATE_FORMAT(b.ending,'2016-%m-%d') <= '2015-12-27')
ORDER BY base_price DESC
And here are some sample dates for each season: '2016-01-08','2015-12-27','2016-04-14','2015-11-29','2016-04-15','2015-09-01','2016-09-02','2015-11-26','2016-10-10','2016-03-18','2016-06-22','2015-06-15'
Thank a lot

Displaying records from database by quarter in mysql

I have a table named nca_totals.
Table: nca_totals
+----------+-----------+------------+--------------+
| total_id | nca_total | nca_date | account_type |
+----------+-----------+------------+--------------+
| 13 | 10450 | 2015-01-21 | DBP-TRUST |
| 14 | 5000 | 2015-02-05 | DBP-TRUST |
| 15 | 7000 | 2015-04-02 | DBP-TRUST |
| 16 | 4000 | 2015-05-02 | DBP-TRUST |
+----------+-----------+------------+--------------+
Now I want to display all the data by quarter base on its date. Let's say I want to display all the records who belong to 1st Quarter like this:
+----------+-----------+------------+--------------+
| total_id | nca_total | nca_date | account_type |
+----------+-----------+------------+--------------+
| 13 | 10450 | 2015-01-21 | DBP-TRUST |
| 14 | 5000 | 2015-02-05 | DBP-TRUST |
+----------+-----------+------------+--------------+
This date belongs to the 1st quarter of the year (Jan, Feb, March). I only have this query to select the date and return its quarter number as:
SELECT QUARTER('2015-01-11'); /* returns 1 */
How can I combine that query to display all the records by quarter ? Can anyone help ? Thanks.
select *
from nca_totals
where QUARTER(nca_date) = 1
SELECT
CEIL(MONTH(`nca_date`) / 3) AS `quarter`
FROM `nca_totals`;