Question

I got a problem with a SQL query that I can't seem to solve.

I have a table with orders, the order number is unique in the first table, which looks like this:

+-------+------------+
| Order | Orderdate  |
+-------+------------+
| 10122 | 19.03.2013 |
| 10123 | 15.03.2013 |
| 10124 | 19.03.2013 |
| 10125 | 17.03.2013 |
| 10126 | 07.03.2013 |
| 10127 | 01.03.2013 |
| 10128 | 16.03.2013 |
| 10129 | 10.03.2013 |
| 10130 | 22.03.2013 |
+-------+------------+

The second table has status updates for the order:

+---------+----------------+--------------+------------+
|  Order  |  Statuschange  |  Changedate  | Changetype |
+---------+----------------+--------------+------------+
|   10127 |             12 |              | Admin      |
|   10127 |              3 |  04.03.2013  | Packaging  |
|   10127 |              4 |  10.03.2013  | Shipping   |
|   10127 |              5 |  13.03.2013  | Packaging  |
|   10127 |              5 |  15.03.2013  | Shipping   |
|   10127 |              6 |  19.03.2013  | Admin      |
|   10127 |              7 |  24.03.2013  | Shipping   |
|   10127 |              8 |  25.03.2013  | Admin      |
|   10127 |              8 |  26.03.2013  | Packaging  |
|   10127 |              8 |  27.03.2013  | Admin      |
|   10127 |              8 |  29.03.2013  | Shipping   |
|   10127 |              8 |  30.03.2013  | Shipping   |
|   10127 |             12 |  01.07.2013  | Shipping   |
|   10127 |              8 |  02.07.2013  | Shipping   |
+---------+----------------+--------------+------------+

From that table, I want to get the row that has the highest number in statuschange and if there are several of them then the one with the highest date. I also want the results of this to be restricted to one Changetype, e.g. Shipping.

The problem is the second table does not have a unique identifier.

My final query output should look like this:

+-------+------------+--------------+------------+------------+
| Order | Orderdate  | Statuschange | Changedate | Changetype |
+-------+------------+--------------+------------+------------+
| 10127 | 01.03.2013 |           12 | 01.07.2013 |  Shipping  |
+-------+------------+--------------+------------+------------+

Thus far I've only been able to get the highest status change but not both the date of the change and the status number of the change.

Thank you in advance for your help.

Was it helpful?

Solution

If your DBMS supports WITH clauses and window functions, you can use

WITH a AS (
SELECT o.Order,
       o.Orderdate,
       s.Statuschange,
       s.Changedate,
       s.Changetype,
       Row_number() OVER(partition by o.Order
                         order by s.statuschange desc, s.changedate desc)
                 as no
  FROM Orders o
       JOIN Statuschange s ON o.Order = s.Order
 WHERE s.Changetype = 'Shipping'
)
SELECT Order,
       Orderdate,
       Statuschange,
       Changedate,
       Changetype
  FROM a
 WHERE no = 1

Row_number() over(...) does the main work here: it first partitions the result set into partitions, where all records having the same value of o.Order get to the same partition. Then, within each partition, it numbers the records starting from 1, ordered first by s.statuschange descending, and those with the same s.statuschange value by s.changedate descending.

Finally, the outer select just excludes all the records not having number 1 via is WHERE clause, which effectively returns the records with the maximum changedate of those having the maximum statuschange for each Order.

This assumes the following - which is not absolutely clear from your question:

  • You want to have the entry with the maximum changedate of those having the maximum statuschange per order. (Reading your question literally, you request the entry with the maximum changedate of those having the maximum statuschange across all orders. If that would really be your request, you should omit the partition by o.Order.)
  • You want to see the Changetype in the result (which you did not state, your expected result does not contain this column).

OTHER TIPS

;WITH ff AS
(
    SELECT ROW_NUMBER() OVER(PARTITION BY Order ORDER BY Statuschange DESC, Changedate DESC) num, *
    FROM [second table]
)
    SELECT f.Order, f.Orderdate, s.Statuschange, s.Changedate  
    FROM [first table] f
    LEFT JOIN  ff s on f.Order = s.Order AND s.num > 1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top