简体   繁体   中英

In SQL How can I get Sums for two sets of date ranges

So I have this as a straight forward way to get the top 10 selling items for a date range:

SELECT TOP 10 Sku, Title, SUM(Qty) as SoldQty, COUNT(Qty) as SalesCount
FROM Sales
WHERE SaleDate BETWEEN @StartDate AND @EndDate
GROUP BY Sku, Title
ORDER BY SUM(Qty) DESC

Now what I want is two more columns that show SoldQty and SalesCount for same date range 30 days prior or the previous year etc. I am trying to avoid loops or multiple trips to the server if possible.

I was thinking it would be some form of this:

SELECT TOP 10 Sku, Title, SUM(Qty) as SoldQty, COUNT(Qty) as SalesCount
FROM Sales
WHERE Sku IN
(
    SELECT TOP 10 Sku
    FROM Sales
    WHERE SaleDate BETWEEN @StartDate AND @EndDate
    GROUP BY Sku
    ORDER BY SUM(Qty) DESC
)
AND SaleDate BETWEEN @StartDate AND @EndDate
GROUP BY Sku, Title
ORDER BY SUM(Qty) DESC

But I can't think of how to use that set created in the IN clause to get the other data I need.

Another way I was thinking might work was where the Sku can be referenced like this:

SELECT TOP 10 Sku as TopSku, Title, SUM(Qty) as SoldQty, COUNT(Qty) as SalesCount,
(
    SELECT SUM(Qty)
    FROM Sales
    WHERE Sku = TopSku
    AND SaleDate BETWEEN DATEADD(DAY, -30, @StartDate) AND DATEADD(DAY, -30, @EndDate)
) as PrevSoldQty,
(
    SELECT Count(Qty)
    FROM Sales
    WHERE Sku = TopSku
    AND SaleDate BETWEEN DATEADD(DAY, -30, @StartDate) AND DATEADD(DAY, -30, @EndDate)
) as PrevSalesCount

FROM Sales
WHERE SaleDate BETWEEN @StartDate AND @EndDate
GROUP BY Sku, Title
ORDER BY SUM(Qty) DESC

Any point in the right direction would be nice.

Consider derived tables where first aggregate query retrieves top 10 SKUs and second aggregate query matches those same SKUs for previous date range:

SELECT s.Sku, s.Title, s.SoldQty, s.SalesCount, p.PrevSoldQty, p.PrevSalesCount
FROM
(
    SELECT TOP 10 Sku, Title, SUM(Qty) As SoldQty, COUNT(Qty) As SalesCount
    FROM Sales
    WHERE SaleDate BETWEEN @StartDate AND @EndDate
    GROUP BY Sku, Title
    ORDER BY SUM(Qty) DESC
) As s
INNER JOIN
(
    SELECT Sku, Title, SUM(Qty) As PrevSoldQty, COUNT(Qty) As PrevSalesCount
    FROM Sales
    WHERE SaleDate BETWEEN DATEADD(DAY, -30, @StartDate) AND DATEADD(DAY, -30, @EndDate)
    GROUP BY Sku, Title
) As p
ON s.Sku = p.Sku AND s.Title = p.Title

Alternatively, you can adjust second query slightly for correlated subqueries using table aliases. However, this is slightly less efficient since subqueries are run for every row and not in one call across all rows

SELECT TOP 10 s.Sku, s.Title, SUM(s.Qty) as SoldQty, COUNT(s.Qty) as SalesCount,
(
    SELECT SUM(sub.Qty)
    FROM Sales sub
    WHERE sub.Sku = s.Sku
    AND sub.SaleDate BETWEEN DATEADD(DAY, -30, @StartDate) AND DATEADD(DAY, -30, @EndDate)
) as PrevSoldQty,
(
    SELECT Count(sub.Qty)
    FROM Sales sub
    WHERE sub.Sku = s.Sku
    AND sub.SaleDate BETWEEN DATEADD(DAY, -30, @StartDate) AND DATEADD(DAY, -30, @EndDate)
) as PrevSalesCount

FROM Sales s
WHERE s.SaleDate BETWEEN @StartDate AND @EndDate
GROUP BY s.Sku, s.Title
ORDER BY SUM(s.Qty) DESC

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