How to find intersection time of multiple time periods? - mysql

How we can find the intersection time of multiple times in mysql? I have this table:
Input:
id | circuit_id | downtime | uptime | duration | Location
---+------------+-----------------+-----------------+----------+----------
1 | 1 | 6/12/2019 11:22 | 6/12/2019 11:27 | 0:05:00 | Bhopal
2 | 2 | 6/12/2019 04:55 | 6/12/2019 07:19 | 2:24:00 | Bhopal
3 | 3 | 6/04/2019 17:59 | 6/06/2019 18:57 | 48:58:00 | Bhopal
4 | 4 | 6/02/2019 03:06 | 6/02/2019 03:12 | 0:06:00 | Bhopal
5 | 1 | 6/01/2019 19:49 | 6/01/2019 20:00 | 0:11:00 | Bhopal
6 | 2 | 5/24/2019 14:59 | 5/24/2019 15:03 | 0:04:00 | Bhopal
7 | 3 | 5/19/2019 03:15 | 5/19/2019 03:54 | 0:39:00 | Bhopal
8 | 4 | 5/15/2019 19:47 | 5/15/2019 19:50 | 0:03:00 | Bhopal
9 | 1 | 5/10/2019 01:21 | 5/10/2019 03:52 | 0:31:00 | Bhopal
10 | 2 | 5/10/2019 02:55 | 5/10/2019 03:37 | 2:42:00 | Bhopal
11 | 3 | 5/10/2019 03:18 | 5/10/2019 04:37 | 1:19:00 | Bhopal
12 | 4 | 5/10/2019 03:20 | 5/10/2019 03:30 | 1:25:00 | Bhopal
13 | 1 | 5/09/2019 05:06 | 5/09/2019 14:17 | 9:11:00 | Bhopal
14 | 2 | 5/09/2019 04:31 | 5/09/2019 04:34 | 0:03:00 | Bhopal
15 | 3 | 4/17/2019 18:37 | 4/17/2019 18:44 | 0:07:00 | Bhopal
16 | 6 | 4/17/2019 17:23 | 4/17/2019 18:05 | 0:42:00 | Delhi
17 | 7 | 4/17/2019 17:00 | 4/17/2019 17:05 | 0:05:00 | Delhi
18 | 8 | 4/10/2019 06:16 | 4/10/2019 06:22 | 0:06:00 | Delhi
19 | 9 | 4/10/2019 02:20 | 4/10/2019 02:45 | 0:25:00 | Delhi
20 | 6 | 4/08/2019 23:01 | 4/08/2019 23:05 | 0:04:00 | Delhi
21 | 7 | 4/05/2019 11:20 | 4/05/2019 11:27 | 0:07:00 | Delhi
22 | 8 | 4/04/2019 01:16 | 4/04/2019 01:27 | 0:11:00 | Delhi
23 | 9 | 4/02/2019 16:30 | 4/02/2019 16:31 | 0:01:00 | Delhi
How to check date-wise and location-wise which is the overlap of times? If all circuits are down within the same time span, then treat it as down, otherwise as up. I only need downtime data.
Expected output:
Bhopal on 05/10/2019 is down for ten minutes 00:10, as all four circuits are down between 03:20 to 03:30 on that particular day.
Location | downtime | date
---------+----------+-----------
Bhopal | 00:10 | 2019-05-10

You could use a self-join to match overlaps, and a having clause to filter for those that include all links.
To get the total number of circuits, you could do another self-join to find all circuits that have ever appeared in the table, per location:
select a.location,
num_circuits,
a.downtime,
min(b.uptime) uptime,
timediff(min(b.uptime), a.downtime) duration,
count(distinct b.circuit_id) num_circuits_down
from tbl a
inner join tbl b
on a.location = b.location
and a.downtime between b.downtime and b.uptime
inner join (
select location, count(distinct circuit_id) num_circuits
from tbl
group by location
) c
on a.location = c.location
group by a.location, num_circuits, a.downtime
having count(distinct b.circuit_id) = num_circuits;
It would be better to have a separate reference-table which lists the circuits per location (4 records per location in your case).
Then the above query would select from that reference table, so instead of:
select location, count(distinct circuit_id) num_circuits
from tbl
group by location
... you would do:
select location, count(distinct circuit_id) num_circuits
from reftable
group by location
That will make the above query more efficient and reliable.

Related

MySQL Min Max deduction

I have a simple table that used to store fuel issuing details for different vehicles as follows:
+----+------------+-----+---------------+-------------+
| id | vehicle_no | qty | meter_reading | date_issued |
+----+------------+-----+---------------+-------------+
| 1 | 366 | 50 | 10500 | 2019-09-01 |
| 2 | 366 | 50 | 11020 | 2019-09-02 |
| 3 | 367 | 25 | 25000 | 2019-09-03 |
| 4 | 366 | 50 | 11450 | 2019-09-04 |
| 5 | 368 | 50 | 6000 | 2019-09-05 |
+----+------------+-----+---------------+-------------+
02) Then I need to find no of Kilometers run against issued sum of fuel quantities.
03) I used the following query
select f1.vehicle_no, (select f1.meter_reading-f2.meter_reading)/sum(qty) from fuel f1) from fuel f2 group by vehicle_no
04) I want to get the desired output as follows :
As an example :
the meter reading of id=4 - meter reading of id=2 is 430 Kilometers
the meter reading of id=4 - meter reading of id=1 is 950 Kilometers
the meter reading of id=2 - meter reading of id=1 is 520 Kilometers
But I did not get the expected result. Can anyone help me ?
With a self join:
select
f.id,
ff.id,
f.vehicle_no,
f.date_issued,
ff.date_issued,
f.meter_reading - ff.meter_reading as dif
from fuel f inner join fuel ff
on ff.vehicle_no = f.vehicle_no and ff.date_issued < f.date_issued
See the demo.
Results:
> id | id | vehicle_no | date_issued | date_issued | dif
> -: | -: | ---------: | :------------------ | :------------------ | --:
> 2 | 1 | 366 | 2019-09-02 00:00:00 | 2019-09-01 00:00:00 | 520
> 4 | 1 | 366 | 2019-09-04 00:00:00 | 2019-09-01 00:00:00 | 950
> 4 | 2 | 366 | 2019-09-04 00:00:00 | 2019-09-02 00:00:00 | 430

How to get the opposite of a join?

I am trying to get the rows that don't exist in one table where one table called schedules (match_week, player_home_id, player_away_id) and the other table called match (match_week, Winner_id, Defeated_id) are joined. The players look at their schedule and play a match. I am trying to get a list of the scheduled matches that do not exist in the match table. The IDs in the match table can be in either column Winner_id or Defeated_id.
I have reviewed a number of Stack Exchange examples, but most use "IS NULL" and I don't have null values. I have used a Join that does give the output of the matches played. I would like the matches that have not been played.
CSV - wp_schedule_test
+----+------------+--------------+--------------+-----------------+-----------------+
| ID | match_week | home_player1 | away_player1 | player1_home_id | player1_away_id |
+----+------------+--------------+--------------+-----------------+-----------------+
| 1 | WEEK 1 | James Rives | Dale Hemme | 164 | 169 |
| 2 | WEEK 1 | John Head | David Foster | 81 | 175 |
| 3 | WEEK 1 | John Dalton | Eric Simmons | 82 | 23 |
| 4 | WEEK 2 | John Head | James Rives | 81 | 164 |
| 5 | WEEK 2 | Dale Hemme | John Dalton | 169 | 82 |
| 6 | WEEK 2 | David Foster | Eric Simmons | 175 | 23 |
| 7 | WEEK 3 | John Dalton | James Rives | 82 | 164 |
| 8 | WEEK 3 | John Head | Eric Simmons | 81 | 23 |
| 9 | WEEK 3 | Dale Hemme | David Foster | 169 | 175 |
| 10 | WEEK 4 | Eric Simmons | James Rives | 23 | 164 |
| 11 | WEEK 4 | David Foster | John Dalton | 175 | 82 |
| 12 | WEEK 4 | Dale Hemme | John Head | 169 | 81 |
+----+------------+--------------+--------------+-----------------+-----------------+
CSV - wp_match_scores_test
+----+------------+------------+------------+
| ID | match_week | player1_id | player2_id |
+----+------------+------------+------------+
| 5 | WEEK 1 | 82 | 23 |
| 20 | WEEK 1 | 164 | 169 |
| 21 | WEEK 2 | 164 | 81 |
| 25 | WEEK 2 | 82 | 169 |
| 61 | WEEK 3 | 175 | 169 |
| 62 | WEEK 4 | 175 | 82 |
| 69 | WEEK 2 | 175 | 23 |
| 85 | WEEK 3 | 164 | 82 |
| 86 | WEEK 4 | 164 | 23 |
+----+------------+------------+------------+
The output from the mysql query are the matches that have been played. I am trying to figure out how to list the matches that have not been played from the table Schedule.
CSV - MySQL Output
+------------+------------+------------+
| match_week | player1_id | player2_id |
+------------+------------+------------+
| WEEK 1 | 164 | 169 |
| WEEK 1 | 82 | 23 |
| WEEK 2 | 164 | 81 |
| WEEK 2 | 82 | 169 |
| WEEK 2 | 175 | 23 |
| WEEK 3 | 175 | 169 |
| WEEK 3 | 164 | 82 |
| WEEK 4 | 175 | 82 |
| WEEK 4 | 164 | 23 |
+------------+------------+------------+
MYSQL
select DISTINCT ms.match_week, ms.player1_id , ms.player2_id FROM
wp_match_scores_test ms
JOIN wp_schedules_test s
ON (s.player1_home_id = ms.player1_id or s.player1_away_id =
ms.player2_id)
Order by ms.match_week
The expected output is:
CSV - Desired Output
+------------+----------------+----------------+
| match_week | player_home_id | player_away_id |
+------------+----------------+----------------+
| WEEK 1 | 81 | 175 |
| WEEK 3 | 81 | 23 |
| WEEK 4 | 169 | 81 |
+------------+----------------+----------------+
The added code I would like to use is
SELECT s.*
FROM wp_schedules_test s
WHERE NOT EXISTS
(select DISTINCT ms.match_week, ms.player1_id , ms.player2_id FROM
wp_match_scores_test ms
JOIN wp_schedules_test s
ON (s.player1_home_id = ms.player1_id or s.player1_away_id =
ms.player2_id)
Order by ms.match_week)
Unfortunately, the output yields "No Rows"
You can use a LEFT JOIN to achieve the desired results, joining the two tables on matching player ids (noting that player id values in wp_match_scores_test can correspond to either player1_home_id or player1_away_id in wp_schedules_test). If there is no match, the result table will have NULL values from the wp_match_scores_test table values, and you can use that to select the matches which have not been played:
SELECT sch.*
FROM wp_schedule_test sch
LEFT JOIN wp_match_scores_test ms
ON (ms.player1_id = sch.player1_home_id
OR ms.player2_id = sch.player1_home_id)
AND (ms.player1_id = sch.player1_away_id
OR ms.player2_id = sch.player1_away_id)
WHERE ms.ID IS NULL
Output:
ID match_week home_player1 away_player1 player1_home_id player1_away_id
2 Week 1 John Head David Foster 81 175
8 Week 3 John Head Eric Simmons 81 23
12 Week 4 Dale Hemme John Head 169 81
Note that you can also use a NOT EXISTS query, using the same condition as I used in the JOIN:
SELECT sch.*
FROM wp_schedule_test sch
WHERE NOT EXISTS (SELECT *
FROM wp_match_scores_test ms
WHERE (ms.player1_id = sch.player1_home_id
OR ms.player2_id = sch.player1_home_id)
AND (ms.player1_id = sch.player1_away_id
OR ms.player2_id = sch.player1_away_id))
The output of this query is the same. Note though that conditions in the WHERE clause have to be evaluated for every row in the result set and that will generally make this query less efficient than the LEFT JOIN equivalent.
Demo on dbfiddle

MYSQL/Query: How to make table rows into column

I have 3 tables tbl_contestant , tbl_criteria and tbl_judges. And then i have 1 more table combined this 3 table as my result, tbl_score.
tbl_criteria
------------------------
crit_id | criteria_name
16 | sports
tbl_judges
------------------------
judge_id | judge_name
61 | first
62 | second
63 | third
tbl_cotestant
--------------------------------------
con_id | contestant_number | contestant_name |
1 | 1 | john |
2 | 2 | sy |
3 | 3 | Nah |
tbl_score
--------------------------------------------------
score_id | crit_id | judge_id | contestant_number | score
1 | 16 | 61 | 1 | 25
2 | 16 | 61 | 2 | 25
3 | 16 | 61 | 3 | 25
4 | 16 | 62 | 1 | 25
5 | 16 | 62 | 2 | 73
6 | 16 | 62 | 3 | 59
7 | 16 | 63 | 1 | 70
8 | 16 | 63 | 2 | 80
9 | 16 | 63 | 3 | 70
How can i achieve this output, judge_id row turns into column based on crit_id
contestant_number | contestant_name | 16_judge_61 | 16_judge_62 | 16_judge_63 | total
1 | john | 25 | 25 | 70 |
2 | sy | 25 | 73 | 80 |
3 | Nah | 25 | 59 | 70 |
Please correct my query
SELECT DISTINCT(c.contestant_number) , contestant_name , j1.sports as
16_judge_61, j2.sports as 16_judge_62, j3.sports as 16_judge_63 from
tbl_criteria , tbl_score, tbl_contestant c
LEFT JOIN tbl_ // <-- i have no idea how start from here joining those 4 tables together
You could use CASE WHEN to solve this.
SELECT
s.contestant_number,
c.contestant_name,
SUM(CASE WHEN s.crit_id='16' AND s.judge_id='61' THEN s.score END) as 16_judge_61,
SUM(CASE WHEN s.crit_id='16' AND s.judge_id='62' THEN s.score END) as 16_judge_62,
SUM(CASE WHEN s.crit_id='16' AND s.judge_id='63' THEN s.score END) as 16_judge_63,
SUM(s.score) as Total
FROM tbl_score s
INNER JOIN tbl_contestant c ON s.contestant_number = c.contestant_number
GROUP BY s.contestant_number
see SQL Fiddle http://sqlfiddle.com/#!9/9efa5/1

Get first and last record number in every date exists in table

I am trying to show invoices for every single day, so for that purpose I used group by on created date and sum on subtotal. This is how I done it :
SELECT
`main_table`.*,
SUM(subtotal) AS `total_sales`
FROM
`sales_invoice` AS `main_table`
GROUP BY
DATE_FORMAT(created_at, "%m-%y")
Its working, but I also want to get the Invoice # from and Invoice # to for every date. Is it possible to do it with single query ?
EDIT :
Table Structure :
------------------------------------------------
| id | inoice_no | created_at | subtotal
| 1 | 34 | 2015-03-17 05:55:27 | 5
| 2 | 35 | 2015-03-17 12:35:00 | 7
| 3 | 36 | 2015-03-20 01:40:00 | 3
| 4 | 37 | 2015-03-20 07:05:13 | 6
| 5 | 38 | 2015-03-20 10:25:23 | 1
| 6 | 39 | 2015-03-24 12:00:00 | 6
------------------------------------------------
Output
---------------------------------------------------------------
| id | inoice_no | created_at | subtotal | total_sales
| 2 | 35 | 2015-03-17 12:35:00 | 7 | 12
| 5 | 38 | 2015-03-20 10:25:23 | 1 | 10
| 6 | 39 | 2015-03-24 12:00:00 | 6 | 6
-----------------------------------------------------------------
What I Expect
---------------------------------------------------------------
| id | inoice_no | created_at | subtotal | total_sales | in_from | in_to
| 2 | 35 | 2015-03-17 12:35:00 | 7 | 12 | 34 | 35
| 5 | 38 | 2015-03-20 10:25:23 | 1 | 10 | 36 | 38
| 6 | 39 | 2015-03-24 12:00:00 | 6 | 6 | 39 | 39
-----------------------------------------------------------------
If your invoice number is INTEGER then below query will give you the result what you want:
SELECT DATE_FORMAT(A.created_at, "%m-%y") AS InvoiceDate,
MIN(A.invoiveNo) AS FromInvoiceNo,
MAX(A.invoiveNo) AS ToInvoiceNo,
SUM(A.subtotal) AS total_sales
FROM sales_invoice AS A
GROUP BY InvoiceDate;
I guess salesid is primaryid in sales_invoice table.
select * from(
SELECT
`main_table`.*,
SUM(subtotal) AS `total_sales`
FROM
`sales_invoice` AS `main_table`
GROUP BY
DATE_FORMAT(created_at, "%m-%y")
order by main_table.salesid limit 1
union all
SELECT
`main_table`.*,
SUM(subtotal) AS `total_sales`
FROM
`sales_invoice` AS `main_table`
GROUP BY
DATE_FORMAT(created_at, "%m-%y")
order by main_table.salesid desc limit 1
)a

Calculate timediff but exclude weekend

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).