-1

My query:

SELECT
    c.CustID,
    o.OrderID,
    SUM(ol.Qty * ol.Price) AS SUMOrder,
    AVG(SUM(ol.Qty * ol.Price)) OVER (PARTITION BY c.CustID) AS AVGAllOrders,
    COUNT(*) AS Countorders,
    SUM(SUM(ol.Qty * ol.Price)) OVER (PARTITION BY c.CustID) AS SumAllOrders
FROM
    Customer c
LEFT JOIN
    [Order] o ON o.CustID  c.CustID
LEFT JOIN
    OrderLine ol ON ol.OrderID = o.OrderID
GROUP BY
    c.CustID, o.OrderID

AVG and SUM calculations need more depth. Besides calculating it over CustID I need to calculate it over 2 periods. So first half year and second half year. Is that possible with PARTITION BY?

Customer:

CustID Name
10073 Test
10074 Test2

Order:

OrderID CustID OrderDate&Time
VOR0060751 10073 2025-05-07 00:00:00.000
VOR0061499 10073 2025-06-04 00:00:00.000
VOR0061918 10073 2025-06-18 00:00:00.000
VOR0052554 10073 2024-07-17 00:00:00.000

OrderLine:

orderid Orderline OrderSubline Qty Price
VOR0060751 010 000 1.000 15.60
VOR0060751 010 005 1.000 12.27
VOR0060751 020 000 1.000 18.19
VOR0060751 020 005 1.000 14.07
VOR0060751 030 000 1.000 16.19
VOR0060751 030 005 1.000 8.87
VOR0060751 040 000 1.000 20.53
VOR0060751 040 005 1.000 18.01
VOR0060751 050 000 1.000 23.49
VOR0060751 050 005 1.000 14.07
VOR0061499 010 000 1.000 8.88
VOR0061499 020 000 1.000 12.12
VOR0061499 020 005 1.000 21.27
VOR0061499 030 000 4.000 16.68
VOR0061499 040 000 1.000 16.68
VOR0061499 050 000 1.000 10.35
VOR0061499 050 005 1.000 6.29
VOR0061499 060 000 1.000 10.35
VOR0061499 060 005 1.000 8.36
VOR0061499 070 000 2.000 14.29
VOR0061499 070 005 2.000 8.87
VOR0061499 080 000 2.000 15.60
VOR0061499 080 005 2.000 10.23
VOR0061499 090 000 2.000 18.19
VOR0061499 090 005 2.000 17.10
VOR0061499 100 000 1.000 18.19
VOR0061499 100 005 1.000 18.01
VOR0061499 110 000 1.000 0.00
VOR0061499 120 000 1.000 20.53
VOR0061499 120 005 1.000 18.01
VOR0061499 130 000 1.000 16.19
VOR0061499 130 005 1.000 10.23
VOR0061499 140 000 4.000 20.53
VOR0061499 140 005 4.000 14.07
VOR0061499 150 000 2.000 0.00
VOR0061499 160 000 2.000 28.00
VOR0061499 160 005 2.000 38.45
VOR0061918 010 000 1.000 6.58
VOR0061918 010 005 1.000 6.07
VOR0061918 020 000 1.000 6.58
VOR0061918 020 005 1.000 6.07
VOR0061918 030 000 1.000 0.00
VOR0061918 040 000 2.000 10.35
VOR0061918 040 005 2.000 8.36
VOR0061918 050 000 1.000 14.29
VOR0061918 050 005 1.000 8.87
VOR0061918 060 000 1.000 15.60
VOR0061918 060 005 1.000 10.23
VOR0061918 070 000 1.000 18.19
VOR0061918 070 005 1.000 17.10
VOR0061918 080 000 2.000 16.19
VOR0061918 080 005 2.000 8.36
VOR0061918 090 000 2.000 20.53
VOR0061918 090 005 2.000 14.07
VOR0061918 100 000 2.000 20.53
VOR0061918 100 005 2.000 18.01
VOR0061918 105 000 1.000 0.00
VOR0061918 110 000 1.000 23.49
VOR0061918 110 005 1.000 14.07
VOR0052554 010 000 2.000 14.23

Desired result:

Custid OrderID SUMOrder AVGAllOrders LHY Countorders LHY SumAllOrders LHY AVGAllOrders LHY2 Countorders LHY2 SumAllOrders LHY2
10073 VOR0060751 161.29000 414.42333 3 1243.27000 0.00000 0 0.00
10073 VOR0061499 702.04000 414.42333 3 1243.27000 0.00000 0 0.00
10073 VOR0061918 318.19000 414.42333 3 1243.27000 0.00000 0 0.00
10073 VOR0052554 28.46000 414.42333 3 1243.27000 28.46000 1 28.46000
6
  • group by date combined with case and between? Commented Aug 29 at 7:03
  • Yes, it's possible to calculate AVG and SUM over multiple periods using window functions combined with conditional aggregation. You can leverage the PARTITION BY clause in your OVER function to calculate these values per customer and per period (e.g., first half vs. second half of the year). First, modify the query to split the orders into two periods: first half of the year and second half of the year. Then, compute SUM and AVG over these periods using CASE statements. Finally, calculate the AVG and SUM both for the individual order and the entire year. Commented Aug 29 at 7:31
  • 5
    A minimal reproducible example is a great start when asking for SQL assistance. Make it easy to help you! Commented Aug 29 at 7:39
  • 2
    You haven't shown the definition of your table(s) and indexes, without which it's hard to give a good answer. See Why should I provide an MCVE for what seems to me to be a very simple SQL query? Commented Aug 29 at 9:33
  • 1
    Desired output should include AVGHalfYear_1, AVGHalfYear_2 columns. Commented Aug 29 at 11:33

2 Answers 2

1

As mentioned, you just need to include some flag based on date of order (for that I assumed you have OrderDate column in Order table):

CASE WHEN MONTH(o.OrderDate) BETWEEN 1 AND 6 THEN 1 ELSE 2 END

so your query could look like this:

SELECT
    c.CustID,
    o.OrderID,
    v.HalfYear,
    SUM(ol.Qty * ol.Price) AS OrderTotal,
    AVG(SUM(ol.Qty * ol.Price)) 
        OVER (PARTITION BY c.CustID, v.HalfYear
        ) AS AvgOrdersHalfYear,
    COUNT(*) 
        OVER (PARTITION BY c.CustID, v.HalfYear
        ) AS CountOrdersHalfYear,
    SUM(SUM(ol.Qty * ol.Price)) 
        OVER (PARTITION BY c.CustID, v.HalfYear
        ) AS SumOrdersHalfYear
FROM Customer c
LEFT JOIN [Order] o 
    ON o.CustID = c.CustID
LEFT JOIN OrderLine ol 
    ON ol.OrderID = o.OrderID
CROSS APPLY (SELECT CASE WHEN MONTH(o.OrderDate) BETWEEN 1 AND 6 THEN 1 ELSE 2 END AS HalfYear) AS v
GROUP BY
    c.CustID,
    o.OrderID,
    v.HalfYear;

SQL fiddle

If you're using SQL Server version 2025 or newer, you could use very useful function DATE_BUCKET:

SELECT
    c.CustID,
    o.OrderID,
    v.HalfYear,
    SUM(ol.Qty * ol.Price) AS OrderTotal,
    AVG(SUM(ol.Qty * ol.Price)) 
        OVER (PARTITION BY c.CustID, v.HalfYear
        ) AS AvgOrdersHalfYear,
    COUNT(*) 
        OVER (PARTITION BY c.CustID, v.HalfYear
        ) AS CountOrdersHalfYear,
    SUM(SUM(ol.Qty * ol.Price)) 
        OVER (PARTITION BY c.CustID, v.HalfYear
        ) AS SumOrdersHalfYear
FROM Customer c
LEFT JOIN [Order] o 
    ON o.CustID = c.CustID
LEFT JOIN OrderLine ol 
    ON ol.OrderID = o.OrderID
CROSS APPLY (SELECT DATE_BUCKET(month, 6, o.OrderDate) AS HalfYear) AS v
GROUP BY
    c.CustID,
    o.OrderID,
    v.HalfYear;

EDIT Here's updated query accordingly to updated question:

WITH OrderTotals AS (
    SELECT
        o.OrderID,
        o.CustID,
        v.HalfYear,
        SUM(ol.Qty * ol.Price) AS SUMOrder
    FROM [Order] o
    LEFT JOIN OrderLine ol ON ol.OrderID = o.OrderID
    CROSS APPLY (SELECT CASE WHEN MONTH(o.OrderDate) BETWEEN 1 AND 6 THEN 1 ELSE 2 END AS HalfYear) AS v
    -- or for Sql Server 2025 or newer
    -- CROSS APPLY (SELECT DATE_BUCKET(month, 6, o.OrderDate) AS HalfYear) AS v
    GROUP BY o.OrderID, o.CustID, v.HalfYear
),
HalfYearAggregates AS (
    SELECT
        CustID,
        HalfYear,
        AVG(SUMOrder) AS AvgOrdersHalfYear,
        COUNT(*) AS CountOrdersHalfYear,
        SUM(SUMOrder) AS SumOrdersHalfYear
    FROM OrderTotals
    GROUP BY CustID, HalfYear
)
SELECT
    ot.CustID,
    ot.OrderID,
    ot.SUMOrder,
    hy1.AvgOrdersHalfYear AS [AVGAllOrders LHY],
    hy1.CountOrdersHalfYear AS [CountOrders LHY],
    hy1.SumOrdersHalfYear AS [SumAllOrders LHY],
    ISNULL(hy2.AvgOrdersHalfYear, 0) AS [AVGAllOrders LHY2],
    ISNULL(hy2.CountOrdersHalfYear, 0) AS [CountOrders LHY2],
    ISNULL(hy2.SumOrdersHalfYear, 0) AS [SumAllOrders LHY2]
FROM OrderTotals ot
LEFT JOIN HalfYearAggregates hy1
    ON ot.CustID = hy1.CustID AND ot.HalfYear = hy1.HalfYear
LEFT JOIN HalfYearAggregates hy2
    ON ot.CustID = hy2.CustID AND ot.HalfYear <> hy2.HalfYear
ORDER BY ot.CustID, ot.OrderID;
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your reply. I don't have SQL Server version 2025. I don't quite understand how it works. Will it only count the between where the result = 1? How can I use it twice? So i want to calculate it in one query for both half years. So in your example HY will be month 1 to 6 including in year 2025. I also want to calculate it for months 7 to 12 including of the year 2024. How would you tackle this?
Your sample data does not make sense, order VOR0052554 appears only once in test data, why it have count equal 3 for first half, as others that appeared in first half?
0

Your example data is quite poor. Only 1 CustID and only one Year.
However, let's try to consider the task.
First, we aggregate the data in the OrderLine table and then use only these aggregates.
Then, we can skip the Customers table because the data from it is not used in the example, and the CustID column in the Orders table is sufficient for calculations. If necessary, you can connect this table in JOIN clause.

Year data calculated with PARTITION BY year(o.OrderDateTime),o.CustID

    SUM(OrderSum) OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS Sum_Y,

Halfyear data calculated with conditional aggregation like

    SUM(case when month(o.OrderDateTime)<=6 then OrderSum end)
                     OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS Sum_HY1,

Full query

select o.CustID, o.OrderId,
    year(o.OrderDateTime) as yy,
    o.OrderDateTime,
    -- count,SUM,AVG for year
    count(*) OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS Count_Y,
    SUM(OrderSum) OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS Sum_Y,
    AVG(OrderSum) OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS AVG_Y,

    case when month(o.OrderDateTime)<=6 then 1 else 2 end nHY,
    -- count,SUM,AVG for 1 halfyear
    SUM(case when month(o.OrderDateTime)<=6 then 1 else 0 end)
                     OVER(PARTITION BY year(o.OrderDateTime)) AS Count_HY1,
    SUM(case when month(o.OrderDateTime)<=6 then OrderSum end)
                     OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS Sum_HY1,
    AVG(case when month(o.OrderDateTime)<=6 then OrderSum end)
                     OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS AVG_HY1,
    -- count,SUM,AVG for 2 halfyear
    SUM(case when month(o.OrderDateTime)>6  then 1 else 0 end)
                     OVER(PARTITION BY year(o.OrderDateTime)) AS Count_HY2,
    SUM(case when month(o.OrderDateTime)>6 then OrderSum end)
                     OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS Sum_HY2,
    AVG(case when month(o.OrderDateTime)>6 then OrderSum end)
                     OVER (PARTITION BY year(o.OrderDateTime),o.CustID) AS AVG_HY2
FROM  [Orders] o
LEFT JOIN
  (
  SELECT 
    ol1.OrderID,
    SUM(ol1.Qty * ol1.Price) AS OrderSum
  FROM  OrderLine ol1 
  GROUP BY ol1.OrderID
) ol ON ol.OrderID = o.OrderID
CustID OrderId yy OrderDateTime Count_Y Sum_Y AVG_Y nHY Count_HY1 Sum_HY1 AVG_HY1 Count_HY2 Sum_HY2 AVG_HY2
10073 VOR0060751 2025 2025-05-07 00:00:00.000 4 1271.73 317.9325 1 3 1243.27 414.423333333333 1 28.46 28.46
10073 VOR0061499 2025 2025-06-04 00:00:00.000 4 1271.73 317.9325 1 3 1243.27 414.423333333333 1 28.46 28.46
10073 VOR0061918 2025 2025-06-18 00:00:00.000 4 1271.73 317.9325 1 3 1243.27 414.423333333333 1 28.46 28.46
10073 VOR0052554 2025 2025-07-17 00:00:00.000 4 1271.73 317.9325 2 3 1243.27 414.423333333333 1 28.46 28.46
[fiddle](https://dbfiddle.uk/kEhQATc0)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.