Reputation: 57
I have an SQL table with holiday bus travel times. This table combines the outgoing trip and the return trip (Option 0 is going, Option 1 is returning), it also offers multiple choices to the user (Option2 counts the options: 3 going trips and 2 return trips). Each trip may span multiple rows, because the table lists all in between stops:
Going:
Return
The Option column shows if a trip is going or returning. The Option2 column matches the options together. The Option3 column shows the correct order of each option.
+----+---------------------+---------------------+------------------+----------------+--------------+---------------+---------------+
| ID | DepartureDateTime | ArrivalDateTime | Departure | Arrival | Option | Option2 | Option3 |
+----+---------------------+---------------------+------------------+----------------+--------------+---------------+---------------+
| 72 | 2013-10-01 13:45:00 | 2013-10-02 16:40:00 | London | Amsterdam | 0 | 0 | 0 |
| 73 | 2013-10-02 17:35:00 | 2013-10-03 19:05:00 | Amsterdam | Berlin | 0 | 0 | 1 |
| 74 | 2013-10-01 17:00:00 | 2013-10-02 19:50:00 | London | Zurich | 0 | 1 | 0 |
| 75 | 2013-10-02 21:10:00 | 2013-10-03 22:40:00 | Zurich | Berlin | 0 | 1 | 1 |
| 76 | 2013-10-01 06:00:00 | 2013-10-02 08:40:00 | London | Paris | 0 | 2 | 0 |
| 77 | 2013-10-02 12:30:00 | 2013-10-03 14:05:00 | Paris | Rome | 0 | 2 | 1 |
| 78 | 2013-10-03 12:30:00 | 2013-10-04 14:05:00 | Rome | Berlin | 0 | 2 | 2 |
| 79 | 2013-10-10 14:50:00 | 2013-10-11 16:30:00 | Berlin | Amsterdam | 1 | 0 | 0 |
| 80 | 2013-10-11 17:05:00 | 2013-10-12 17:50:00 | Amsterdam | London | 1 | 0 | 1 |
| 81 | 2013-10-10 06:45:00 | 2013-10-11 08:25:00 | Berlin | Zurich | 1 | 1 | 0 |
| 82 | 2013-10-11 15:20:00 | 2013-10-12 16:05:00 | Zurich | London | 1 | 1 | 1 |
+----+---------------------+---------------------+------------------+----------------+--------------+---------------+---------------+
I would like two different queries:
1) Sort the table based on two things: a. for outgoing: the initial depature of the trip (going out of London), without messing with the order of the subsequent stops. b. for returning: the arrival of the final return trip (going into London), again without messing with the order of the subsequent stops.
2) Return only the trips that match a specific date/time range: initial departure (going out of London) and final return (going into London). For example, show trips that have a morning departure and an evening arrival.
Please let me know if you need more details or if I missed something.
Thank you for your help in advance.
edit 1
Please read my entire post. The important thing here, is that the rows are related to each other. For example, the two rows below MUST be "together", the application that I'm dealing with depends on the order to be correct:
+----+---------------------+---------------------+------------------+----------------+--------------+---------------+---------------+
| ID | DepartureDateTime | ArrivalDateTime | Departure | Arrival | Option | Option2 | Option3 |
+----+---------------------+---------------------+------------------+----------------+--------------+---------------+---------------+
| 72 | 2013-10-01 13:45:00 | 2013-10-02 16:40:00 | London | Amsterdam | 0 | 0 | 0 |
| 73 | 2013-10-02 17:35:00 | 2013-10-03 19:05:00 | Amsterdam | Berlin | 0 | 0 | 1 |
That means, sorting by the Departure date is not possible, because the rows would get mixed up.
So, if I wanted to sort the above trip based on the Departure, first would appear the London to Berlin via Paris trip because it departs at 6 in the morning:
+----+---------------------+---------------------+------------------+----------------+--------------+---------------+---------------+
| ID | DepartureDateTime | ArrivalDateTime | Departure | Arrival | Option | Option2 | Option3 |
+----+---------------------+---------------------+------------------+----------------+--------------+---------------+---------------+
| 76 | 2013-10-01 06:00:00 | 2013-10-02 08:40:00 | London | Paris | 0 | 2 | 0 |
| 77 | 2013-10-02 12:30:00 | 2013-10-03 14:05:00 | Paris | Rome | 0 | 2 | 1 |
| 78 | 2013-10-03 12:30:00 | 2013-10-04 14:05:00 | Rome | Berlin | 0 | 2 | 2 |
| 72 | 2013-10-01 13:45:00 | 2013-10-02 16:40:00 | London | Amsterdam | 0 | 0 | 0 |
| 73 | 2013-10-02 17:35:00 | 2013-10-03 19:05:00 | Amsterdam | Berlin | 0 | 0 | 1 |
The partial table above shows how the sorted result would look like. Basically, the sorting algorithm should take into consideration the row with the initial departure and ignore the other rows from the sorting, but the end result should have the related stops in the trip "below" the initial trip.
Does that sound horrible or what?
Any help would be appreciated.
edit 2
As requested, I am using MySQL 5.1.
edit 3
The member @fancyPants has solved the first query. I made a slight modification to take into consideration the change from Option=0 to Option=1:
SELECT
`ID`, `DepartureDateTime`, `ArrivalDateTime`, `Departure`, `Arrival`, `Option`, `Option2`, `Option3`
FROM (
SELECT
t.*,
CASE WHEN Option != @prev OR Option2 != @prev2 THEN @min_date := DepartureDateTime ELSE @min_date END as min_date,
CASE WHEN Option2 = @prev2 THEN @counter := @counter + 1 ELSE @counter := 0 END as counter,
@prev := Option, @prev2 := Option2
FROM Table1 t
, (SELECT @min_date:=(SELECT DepartureDateTime FROM Table1 ORDER BY `Option`, Option2, Option3 LIMIT 1), @counter:=0, @prev:=NULL, @prev2:=NULL) vars
order by `Option`, Option2, Option3
) sq
ORDER BY min_date, counter
thank you fancyPants, AMAZING WORK!
Unfortunately, I wasn't clear enough about the second query. What I need, is to built on top of the first query (thus results are sorted) and then limit results based on a date-time range.
Upvotes: 0
Views: 172
Reputation: 51908
This is not so easy, here's what I came up with (assuming MySQL):
Sort the table based on two things: a. for outgoing: the initial depature of the trip (going out of London), without messing with the order of the subsequent stops:
SELECT
`ID`, `DepartureDateTime`, `ArrivalDateTime`, `Departure`, `Arrival`, `Option`, `Option2`, `Option3`
FROM (
SELECT
t.*,
CASE WHEN Option2 != @prev THEN @min_date := DepartureDateTime ELSE @min_date END as min_date,
CASE WHEN Option2 = @prev THEN @counter := @counter + 1 ELSE @counter := 0 END as counter,
@prev := Option2
FROM Table1 t
, (SELECT @min_date:=(SELECT DepartureDateTime FROM Table1 ORDER BY `Option`, Option2, Option3 LIMIT 1), @counter:=0, @prev:=NULL) vars
order by `Option`, Option2, Option3
) sq
ORDER BY min_date, counter
for returning:
SELECT
`ID`, `DepartureDateTime`, `ArrivalDateTime`, `Departure`, `Arrival`, `Option`, `Option2`, `Option3`
FROM (
SELECT
t.*,
CASE WHEN Option2 != @prev THEN @min_date := ArrivalDateTime ELSE @min_date END as min_date,
CASE WHEN Option2 = @prev THEN @counter := @counter + 1 ELSE @counter := 0 END as counter,
@prev := Option2
FROM Table1 t
, (SELECT @min_date:=(SELECT ArrivalDateTime FROM Table1 ORDER BY `Option`, Option2, Option3 LIMIT 1), @counter:=0, @prev:=NULL) vars
order by `Option`, Option2, Option3
) sq
ORDER BY min_date, counter
For your second question, if I understood it correct you want something like this:
SELECT
t1.DepartureDateTime AS t1dep,
t2.ArrivalDateTime AS t2arr
, t1.*, t2.*
FROM Table1 t1
INNER JOIN Table1 t2 ON t1.Option = t2.Option AND t1.Option2 = t2.Option2
WHERE t1.Option3 = (SELECT MIN(Option3) FROM Table1 t3 WHERE t1.Option = t3.Option AND t1.Option2 = t3.Option2)
AND t2.Option3 = (SELECT MAX(Option3) FROM Table1 t3 WHERE t1.Option = t3.Option AND t1.Option2 = t3.Option2)
AND t1.DepartureDateTime BETWEEN '2013-10-01 05:00:00' AND '2013-10-01 07:00:00'
AND t2.ArrivalDateTime BETWEEN '2013-10-04 14:00:00' AND '2013-10-04 15:00:00'
This query returns the minimum datetime of departure, meaning the departure date of the first station of a trip and the arrival date for the last station in one line. Then you can simply adjust where clause.
EDIT: Are you looking for something like this?
SELECT
l.* FROM
(
SELECT
`ID`, `DepartureDateTime`, `ArrivalDateTime`, `Departure`, `Arrival`, `Option`, `Option2`, `Option3`
,min_date, counter
FROM (
SELECT
t.*,
CASE WHEN `Option` != @prev OR Option2 != @prev2 THEN @min_date := DepartureDateTime ELSE @min_date END as min_date,
CASE WHEN Option2 = @prev2 THEN @counter := @counter + 1 ELSE @counter := 0 END as counter,
@prev := `Option`, @prev2 := Option2
FROM Table1 t
, (SELECT @min_date:=(SELECT DepartureDateTime FROM Table1 ORDER BY `Option`, Option2, Option3 LIMIT 1), @counter:=0, @prev:=NULL, @prev2:=NULL) vars
order by `Option`, Option2, Option3
) sq
) l
INNER JOIN
(SELECT `Option`, Option2 FROM Table1 WHERE DepartureDateTime BETWEEN '2013-10-02 11:30:00' AND '2013-10-02 13:00:00'
OR ArrivalDateTime BETWEEN '2013-10-03 14:00:00' AND '2013-10-03 14:15:00'
) r
ON l.`Option` = r.`Option` AND l.Option2 = r.Option2
ORDER BY min_date, counter
Upvotes: 2
Reputation: 1872
for 1 st question - going query
select * from time_table
where option = 0
order by DepartureDateTime, Option2, Option3;
1st question - returning query
select * from time_table
where option = 1
order by ArrivalDateTime, Option2, Option3;
This result base on understand what you asked. its not really clear.
Please add some details for 2nd question. cant understand the issue. give example with data.
Upvotes: 0