Order by one column and then by another column - sql-server-2014

I have an SQL Fiddle and the table looks like below
TicketId EmployeeId BookingRef DepartureDate DepartureTime
1 1110341 8662225387 2017-10-16 14:00:00.0000000
2 1110341 8662225388 2017-10-17 14:36:00.0000000
3 1110341 8662225388 2017-10-17 21:39:00.0000000
4 1110341 8662225389 2017-10-12 17:15:00.0000000
5 1110341 8662225390 2017-10-12 18:42:00.0000000
6 1110341 8662225390 2017-10-16 14:15:00.0000000
I want to order it by DepartureDate, DepartureTime and BookingRef however related BookingRef should be partitioned together So the above result should look like
TicketId EmployeeId BookingRef DepartureDate DepartureTime
4 1110341 8662225389 2017-10-12 17:15:00.0000000
5 1110341 8662225390 2017-10-12 18:42:00.0000000
6 1110341 8662225390 2017-10-16 14:15:00.0000000
1 1110341 8662225387 2017-10-16 14:00:00.0000000
2 1110341 8662225388 2017-10-17 14:36:00.0000000
3 1110341 8662225388 2017-10-17 21:39:00.0000000

I'd use a subquery to do your ordering, something like this;
SELECT
t.*
FROM Ticket t
JOIN (SELECT BookingRef, MIN(DepartureDate) MinDeparture FROM Ticket GROUP BY BookingRef) sub
ON t.BookingRef = sub.BookingRef
ORDER BY sub.MinDeparture ASC, t.BookingRef ASC
Which gives the output that you've shown. See it in the fiddle here
This is going to order by the minimum DepartureTime for each BookingRef.

You want to 'Group By'
SELECT column_names FROM table_name WHERE condition GROUP BY
BookingRef ORDER BY column_name;

Related

Finding time difference based on distinct ids in mySQL

I would like to find the day difference between the latest and the 2nd latest distinct order_id for each user.
The intended output would be:
user_id | order_diff
1 | 1
3 | 7
8 | 1
order_diff represents the difference in days between 2 distinct order_id. In the event that there are no two distinct order_id (as in the case for user id 9), the result is not returned.
In this case, the order_diff for user_id 1 is 1 since the day difference between his 2 distinct order_id is 1. However, there is no order_diff for user_id 9 since he has no 2 distinct `order_id'.
This is the dataset:
user_id order_id order_time
1 208965785 2016-12-15 17:14:13
1 201765785 2016-12-14 17:19:05
1 203932785 2016-12-13 20:41:30
1 209612785 2016-12-14 20:14:32
1 208112785 2016-12-14 20:27:08
1 205525785 2016-12-14 17:01:26
1 208812785 2016-12-14 20:18:23
1 206432785 2016-12-11 20:32:20
1 206698785 2016-12-14 10:50:15
2 209524795 2016-11-26 18:06:21
3 206529925 2016-10-01 10:43:57
3 203729925 2016-10-08 10:43:11
4 204876145 2016-09-24 10:23:49
5 203363157 2016-07-13 23:56:43
6 207784875 2017-01-04 12:21:21
7 206437177 2016-06-25 02:40:33
8 202819645 2016-09-09 11:47:27
8 202819645 2016-09-09 11:47:27
8 202819646 2016-09-08 11:47:27
9 205127187 2016-06-05 22:21:18
9 205127187 2016-06-05 22:21:18
11 207874877 2016-06-17 16:49:44
12 204927595 2016-11-28 23:05:40
This is the code that I am currently using:
SELECT e1.user_id,datediff(e1.order_time,e2.time), e1.order_id FROM
sales e1
JOIN
sales e2
ON
e1.user_id=e2.user_id
AND
e1.order_id = (SELECT distinct order_id FROM sales temp1 WHERE temp1.order_id =e1.order_id ORDER BY order_time DESC LIMIT 1)
AND
e2.order_id = (SELECT distinct order_id FROM sales temp2 WHERE temp2.order_id=e2.order_id ORDER BY order_time DESC LIMIT 1 OFFSET 1)
My output does not produce the desired output and it also ignores the cases where order_ids are the same.
Edit: I would also like the query to be extended to larger datasets where the 2nd most recent order_time may not be the min(order_time)
Based on your fiddle:
select user_id,
datediff(max(order_time),
( -- Scalar Subquery to get the 2nd largest order_time
select max(order_time)
from orders as o2
where o2.user_id = o.user_id -- same user
and o2.order_time < max(o.order_time) -- but not the max time
)
) as diff
from orders as o
group by user_id
having diff is not null -- if there's no 2nd largest time diff will be NULL
Following would work:
Schema (MySQL v5.7)
CREATE TABLE orders
(`user_id` int, `order_id` int, `order_time` datetime)
;
INSERT INTO orders
(`user_id`, `order_id`, `order_time`)
VALUES
(1,208965785,'2016-12-15 17:14:13'),
(1,201765785,'2016-12-14 17:19:05'),
(1,203932785,'2016-12-13 20:41:30'),
(1,209612785,'2016-12-14 20:14:32'),
(1,208112785,'2016-12-14 20:27:08'),
(1,205525785,'2016-12-14 17:01:26'),
(1,208812785,'2016-12-14 20:18:23'),
(1,206432785,'2016-12-11 20:32:20'),
(1,206698785,'2016-12-14 10:50:15'),
(2,209524795,'2016-11-26 18:06:21'),
(3,206529925,'2016-10-01 10:43:57'),
(3,203729925,'2016-10-08 10:43:11'),
(4,204876145,'2016-09-24 10:23:49'),
(5,203363157,'2016-07-13 23:56:43'),
(6,207784875,'2017-01-04 12:21:21'),
(7,206437177,'2016-06-25 02:40:33'),
(8,202819645,'2016-09-09 11:47:27'),
(8,202819645,'2016-09-09 11:47:27'),
(8,202819646,'2016-09-08 11:47:27'),
(9,205127187,'2016-06-05 22:21:18'),
(9,205127187,'2016-06-05 22:21:18'),
(11,207874877,'2016-06-17 16:49:44'),
(12,204927595,'2016-11-28 23:05:40');
Query #1
SELECT dt2.user_id,
MIN(datediff(dt2.latest_order_time,
dt2.second_latest_order_time)) AS order_diff
FROM (
SELECT o.user_id,
o.order_time AS latest_order_time,
(SELECT o2.order_time
FROM orders AS o2
WHERE o2.user_id = o.user_id AND
o2.order_id <> o.order_id
ORDER BY o2.order_time DESC LIMIT 1) AS second_latest_order_time
FROM orders AS o
JOIN (SELECT user_id, MAX(order_time) AS latest_order_time
FROM orders
GROUP BY user_id) AS dt
ON dt.user_id = o.user_id AND
dt.latest_order_time = o.order_time
) AS dt2
WHERE dt2.second_latest_order_time IS NOT NULL
GROUP BY dt2.user_id;
| user_id | order_diff |
| ------- | ---------- |
| 1 | 1 |
| 3 | 7 |
| 8 | 1 |
View on DB Fiddle
Details:
We determine maximum order_time for a user_id in a sub-select query (Derived Table). We can alias it as latest_order_time.
We Join this result-set to the orders table. This will help us in considering only the row(s) with maximum value of order_time for a user_id.
Now, we use a Correlated Subquery to determine the maximum order_time value for the same user, out of the rest of order_id value(s). We can alias it as second_latest_order_time.
Finally, use this as a Derived Table again, and remove all the cases where second_latest_order_time is null, and calculate datediff() for the rest.
A final Group By is needed, as your data has multiple entries for a
Here is the solution:
SELECT user_id,
DATEDIFF(MAX(order_time), MIN(order_time)) as order_diff
FROM orders
GROUP BY user_id
HAVING order_diff > 0;
Here is a link to test it.

How to get data from a table even when count(row) is zero? please see the description for more details and the query?

table one
id mandal_name
1 mandal1
2 mandal2
3 mandal3
table address
id mandal_name date
1 mandal1 2017-07-11 12:34:11
2 mandal1 2017-07-11 12:54:45
3 mandal1 2017-07-11 12:23:23
SELECT count(id) as yesterday_count, mandal FROM address WHERE date(date) = '2017-07-11'
Result obviously
3 , mandal1
Expecting result
3 , mandal1
0 , mandal2
0 , mandal3
...
The key is to use an OUTER JOIN - LEFT JOIN in this case.
You can either do
SELECT m.mandal_name, COUNT(a.id) AS yesterday_count
FROM table_one m LEFT JOIN address a
ON m.mandal_name = a.mandal_name
AND a.date >= '2017-07-11'
AND a.date < '2017-07-12'
GROUP BY m.mandal_name;
or
SELECT m.mandal_name, COALESCE(count, 0) AS yesterday_count
FROM table_one m LEFT JOIN (
SELECT mandal_name, COUNT(*) AS count
FROM address
WHERE date >= '2017-07-11'
AND date < '2017-07-12'
) a
ON m.mandal_name = a.mandal_name;
Here is a SQLFiddle demo
Output
| mandal_name | yesterday_count |
|-------------|-----------------|
| mandal1 | 3 |
| mandal2 | 0 |
| mandal3 | 0 |
Further reading - A Visual Explanation of SQL Joins
On a side note - don't use DATE(date) as it makes it impossible to use an index on date column effectively causing a full table scan.
you can query it like this:
SELECT A.mandal_name,IFNULL(COUNT(*),0)
FROM one A
LEFT JOIN address B ON A.mandal_name = B.mandal_name
WHERE DATE(B.date) = '2017-07-11'
GROUP BY A.mandal_name
just substitute your table name and columns to get the result

SAP HANA: days between two Orders

Here is the table ihave, i was trying days between by joining the same table with left join and group by with min difference. I was not so successful.
Customer|Order|Date
1 | 1 |Date1
1 | 2 |Date2
1 | 3 |Date3
1 | 4 |Date4
2 | 1 |Date1
2 | 2 |Date3
2 | 3 |Date6
3 | 1 |Date3
3 | 2 |Date5
Required is:
Customer|Order|Date |diff
1 | 1 |Date1| 0
1 | 2 |Date2| days_betwen(Date2, Date1)
1 | 3 |Date3| days_betwen(Date3, Date2)
1 | 4 |Date4| days_betwen(Date4, Date3)
2 | 1 |Date1| 0
2 | 2 |Date3| days_betwen(Date3, Date1)
2 | 3 |Date6| days_betwen(Date6, Date3)
3 | 1 |Date3| 0
3 | 2 |Date5| days_betwen(Date5, Date3)
I need suggestion with the logic part!
EDIT: What if the order numbers are not sequential?
In first, you need to join the table to itself by Customer and Order fields. Then use DATEDIFF() function to get days number between two dates.
If the Order column is numbered sequentially then solution is simplest:
SELECT
cur.`Customer` AS `Customer`,
cur.`Order` AS `Order`,
cur.`Date` AS `Date`,
DATEDIFF(cur.`Date`, IFNULL(prv.`Date`, cur.`Date`)) AS `DaysPassed`
FROM
MyTable cur
LEFT JOIN
MyTable prv
ON cur.`Customer` = prv.`Customer` AND cur.`Order` = prv.`Order`+ 1;
If the Order column is not numbered sequentially, but next Order value is greater than previous, then you could use greater than or less than operators. Use GROUP BY clause and an aggregate function to return single row for each order. Note, maybe it will be long!
SELECT
comb.`Customer` AS `Customer`,
comb.`curOrder` AS `Order`,
comb.`curDate` AS `Date`,
DATEDIFF(comb.`curDate`, IFNULL(pr.`Date`, comb.`curDate`)) AS `DaysPassed`
FROM
(SELECT
cur.`Customer` AS `Customer`, cur.`Order` AS curOrder, cur.`curDate` AS `Date`, max(prv.`Order`) AS `prvOrder`
FROM
MyTable cur
LEFT JOIN
MyTable prv
ON cur.`Customer` = prv.`Customer` AND cur.`Order` > prv.`Order`
GROUP BY cur.`Order`, cur.`Customer`) comb
LEFT JOIN
MyTable pr
ON pr.`Customer` = comb.`Customer` AND pr.`Order` = comb.prvOrder;
If you use random order number, then it is possible to use Date column instead of Order in the comb subquery to join records by nearest order dates of same customer.
Good luck!

Select on 2 tables return no result?

I have 2 tables :
Table 'annonce' (real estate ads) :
idAnnonce | reference
-----------------------
1 | dupond
2 | toto
Table 'freeDays' (Free days for all ads) :
idAnnonce | date
-----------------------
1 | 2015-06-06
1 | 2015-06-07
1 | 2015-06-09
1 | 2015-06-10
2 | 2015-06-06
2 | 2015-06-07
2 | 2015-06-12
2 | 2015-06-13
I want to select all alvailable ads who have only free days between a start and end date, I have to check each days between this date.
The request :
SELECT DISTINCT
`annonce`.`idAnnonce`, `annonce`.`reference`
FROM
`annonce`, `freeDays`
WHERE
`annonce`.`idAnnonce` = `freeDays`.`idAnnonce`
AND
`freeDays`.`date` = '2015-06-06'
AND
`freeDays`.`date` = '2015-06-07'
Return no result. Where is my error ?
It cant be equal both dates
SELECT DISTINCT a.idAnnonce, a.reference
FROM annonce a
INNER JOIN freeDays f ON a.idAnnonce = f.idAnnonce
WHERE f.date BETWEEN '2015-06-06' AND '2015-06-07'
What Matt is say is correct. You can also do this as alternative:
SELECT DISTINCT a.idAnnonce, a.reference
FROM annonce a
INNER JOIN freeDays f ON a.idAnnonce = f.idAnnonce
WHERE f.date IN('2015-06-06','2015-06-07')
Or like this:
SELECT DISTINCT a.idAnnonce, a.reference
FROM annonce a
INNER JOIN freeDays f ON a.idAnnonce = f.idAnnonce
WHERE f.date ='2015-06-06' OR f.date ='2015-06-07'
This will give you the same result as with an BETWEEN
Your WHERE clause is asking for the impossible!
You are asking for rows where the 'freedays'.'date' value is both 2015-06-06 and 2015-06-07.
AND
freeDays.date = '2015-06-06'
AND
freeDays.date = '2015-06-07'
You need to use BETWEEN:
freeDays.date BETWEEN '2015-06-06' AND '2015-06-07'
AND
freeDays.date = '2015-06-06'
OR
freeDays.date = '2015-06-07'

mysql--- select result that some key is null in join table

I have 2 table in mysql
user_titem
item_id item_name
------------------------
1 a
2 b
3 c
5 d
track
--------------------------------------------------------
track_no member_ID member_track track_type
1 2 1 titem
2 2 2 titem
3 2 3 titem
5 2 13 titem
6 2 5 titem
In track, member_track will refer to item_id, so if i do this select statement:
SELECT track.track_no ,track.track_type, user_titem.item_name ,user_titem.item_id
FROM track
LEFT JOIN user_titem ON track.member_track=user_titem.item_id
WHERE track.track_type = 'titem' and track.member_ID='2'
the result is
result
-----------------------------------
track_no track_type item_name item_id
5 titem NULL NULL
The item_name and item_id is null because in track_no(5), member_track(refer to item_id) is not in user_titem.
Now the problem is, how can i just get the track_no directly in one select statement when the member_track of track_no is null.
The result that i want
result
-----------
track_no
5
How can i solve the problem ?
Just add additional check in WHERE clause:
SELECT track.track_no
FROM track
LEFT JOIN user_titem ON track.member_track=user_titem.item_id
WHERE track.track_type = 'titem' and track.member_ID='2'
AND user_titem.item_id is null
Why dont you try
SELECT track_no FROM track where member_track NOT IN (SELECT item_id FROM user_titem)
I think it will give the same result.