简体   繁体   中英

Struggling with a nested where, group by and min/max in SQL

I have this table in MS Access and need to write a query for a report and am struggling. My SQL is largely unused for at least 5 years, and was never really that good, but I thought I could do this without too much trouble...alas.

Product ProductSubCode OrderDateTime Order Amount
A 1 2021-05-25 11:30 5
A 2 2021-05-25 12:30 50
A 1 2021-05-25 13:30 500
B 1 2021-05-25 09:30 400
B 2 2021-05-25 10:30 40
B 1 2021-05-25 11:30 4
C 1 2021-05-25 13:30 30
C 1 2021-05-25 14:30 300
C 2 2021-05-25 15:30 3
A 2 2021-05-24 11:30 5
A 2 2021-05-24 12:30 50
A 1 2021-05-24 13:30 500
B 1 2021-05-24 09:30 400
B 1 2021-05-24 10:30 40
B 1 2021-05-24 11:30 4
C 1 2021-05-24 13:30 30
C 1 2021-05-24 14:30 300
C 2 2021-05-24 15:30 3

I'm trying to query the above table to display the following results

Product|ProductSubCode|MinYesterday|MaxYesterday|MinTwoDaysAgo|MaxToDaysAgo

ie For each product/sub code, select the min & max order amount for today and yesterday.

What I have so far is as follows;

SELECT distinct Product as masterID,ProductSubCode
(SELECT MIN(Order Amount) FROM TableName WHERE Product = masterID AND DateValue(OrderDateTime) >= DateAdd("d",-1,Date())) AS MinYesterday,
(SELECT MIN(Order Amount) FROM TableName WHERE Product = masterID AND DateValue(OrderDateTime) >= DateAdd("d",-1,Date())) AS MaxYesterday,
(SELECT MIN(Order Amount) FROM TableName WHERE Product = masterID AND DateValue(OrderDateTime) >= DateAdd("d",-2,Date())) AS MinTwoTodayAgo,
(SELECT MIN(Order Amount) FROM TableName WHERE Product = masterID AND DateValue(OrderDateTime) >= DateAdd("d",-2,Date())) AS MaxTwoDaysAgo
FROM TableName
GROUP BY Product, ProductSubCode

I get it, it's definitely wrong but I could really use some help here.

I think you are very close, changed it just a little bit:

  1. It's better to avoid spaces in the column names, so use OrderAmount. If it's not possible to change a column name already, MIN([Order Amount]) will work instead of MIN(Order Amount) .

  2. You have MIN in all the rows, whereas it should be MINs and MAXs.

  3. I changed >= with = because you need a strict equation there

  4. changed column alias masterID to table alias t1

SELECT distinct Product, ProductSubCode,
(SELECT MIN(OrderAmount) FROM TableName WHERE Product = t1.Product AND DateValue(OrderDateTime) = DateAdd("d",-1,Date())) AS MinYesterday,
(SELECT MAX(OrderAmount) FROM TableName WHERE Product = t1.Product  AND DateValue(OrderDateTime) = DateAdd("d",-1,Date())) AS MaxYesterday,
(SELECT MIN(OrderAmount) FROM TableName WHERE Product = t1.Product AND DateValue(OrderDateTime) = DateAdd("d",-2,Date())) AS MinTwoTodayAgo,
(SELECT MAX(OrderAmount) FROM TableName WHERE Product = t1.Product AND DateValue(OrderDateTime) = DateAdd("d",-2,Date())) AS MaxTwoDaysAgo
FROM TableName t1
GROUP BY Product, ProductSubCode

Try with these small adjustments using alias for the table in the subqueries:

SELECT 
    Product,
    ProductSubCode,
    (SELECT MIN(T1.[Order Amount]) FROM TableName AS T1
        WHERE T1.Product = TableName.Product AND DateValue(T1.OrderDateTime) = DateAdd("d",-1,Date())) AS MinYesterday,
    (SELECT MAX(T2.[Order Amount]) FROM TableName AS T2
        WHERE T2.Product = TableName.Product AND DateValue(T2.OrderDateTime) = DateAdd("d",-1,Date())) AS MaxYesterday,
    (SELECT MIN(T3.[Order Amount]) FROM TableName AS T3
        WHERE T3.Product = TableName.Product AND DateValue(T3.OrderDateTime) = DateAdd("d",-2,Date())) AS MinTwoTodayAgo,
    (SELECT MAX(T4.[Order Amount]) FROM TableName AS T4
        WHERE T4.Product = TableName.Product AND DateValue(T4.OrderDateTime) = DateAdd("d",-2,Date())) AS MaxTwoDaysAgo
FROM 
    TableName
GROUP BY 
    Product, 
    ProductSubCode

Use conditional aggregation!

SELECT Product as masterID, ProductSubCode,
       MIN(IIF(OrderDateTime >= DateAdd("d", -1, Date()) AND OrderDateTime < Date(), [Order Amount], NULL) as MinYesterday,
       MAX(IIF(OrderDateTime >= DateAdd("d", -1, Date()) AND OrderDateTime < Date(), [Order Amount], NULL) as MaxYesterday,
       MIN(IIF(OrderDateTime >= Date(), [Order Amount], NULL) as MinToday,
       MIN(IIF(OrderDateTime >= Date(), [Order Amount], NULL) as MaxToday
FROM TableName
WHERE OrderDateTime >= DateAdd("d", -1, Date())
GROUP BY Product, ProductSubCode;

In addition to being more concise, you should find that this has much, much, much better performance.

Note: This particular formulation assumes that you have no future order dates. It is easy enough to extend the WHERE clause to remove future order dates if that is an issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM