SQL 服务器查询以获取出货量排名前 10 的产品、平均值、mtd 和 ytd
SQL Server query to get top 10 products shipped, avg, mtd & ytd
对于库存报告,我需要为最畅销的 10 种产品生成输出
product description in-stock MTD YTD Avg
---------------------------------------------------------------------------
P1 (altp1) product X 100 30 1000 33
P2 (altp2) product Y 10 0 100 9
产品相关表:
- 产品(sku、描述……)
- products_details (sku, altsku, ...)
订单相关表:
- 订单(id,shipped_date,...)
- order_details (id, order_id, product_id, shipped_qty, ....)
仓库库存
- 库存(id,[warehouse_id,product_id,数量,...)
我尝试 SQL 使用连接和子查询,但处理结果花了大约 7 分钟
SELECT TOP 10
p.sku
,p1.alt_sku
,p.description
,wh.qty
,SUM(od.shipped_qty) as YTD
,SUM(od.shipped_qty) as MTD
,AVG(od.shipped_qty) as AvgSales -- how do I get avg of last six months?
FROM product as p
INNER JOIN product_details as p1 ON p.sku = p1.sku
LEFT JOIN inventory as wh on wh.sku = p.sku
LEFT JOIN order_details as od on od.sku= p.sku
LEFT JOIN orders as o on o.order_id = od.order_id
WHERE o.shipped_date >= @YearStart
GROUP BY p.sku, p1.alt_sku, p.description, o.shipped_date, wh.qty, od.shipped_qty
ORDER by MTD DESC
我尝试使用 CTE,它大大加快了查询速度。但是结果出现了重复的skus和double entries
WITH CTE_Summary(product_id, yy, mm, shipped) as (
SELECT
orders.product_id, yy, mm, SUM(orders.shipped_qty) as shipped
FROM (
select o.id
, od.product_id
, SUM(od.shipped_qty) shipped_qty
, year(o.shipped_date) yy
, month(o.shipped_date) mm
from orders o
LEFT JOIN order_details od on od.order_id = o.id
GROUP BY o.id, od.product_id, year(o.shipped_date), month(o.shipped_date)
) AS orders
WHERE orders.yy >= YEAR(GetDate())
GROUP BY orders.product_id, orders.yy, orders.mm
)
SELECT sku.sku, sku.description, sku.alt_sku, sku.instock, summ.avgshipped, summ.YTD, summ.MTD, sku.sku, sku.DESCR, sku.ALTSKU, sku.DESCR, sku.instock
FROM (SELECT top 10 product_id
, AVG(shipped) as avgshipped
, SUM(shipped) as YTD
, SUM(CASE WHEN mm = MONTH(GetDate()) THEN shipped ELSE 0 END) as mtd
from CTE_Summary GROUP BY product_id order by mtd desc, ytd desc) summ
LEFT JOIN (
SELECT p1.sku, p1.description, p2.alt_sku, wh.qty as instock FROM products p1
LEFT JOIN product_details p2 ON p2.product_id = p1.id
LEFT JOIN inventory wh on wh.product_id = p1.id
) sku ON sku.product_id = summ.product_id
但是每个产品 returns 多行(类似这样)
product description in-stock MTD YTD Avg
---------------------------------------------------------------------------
P1 (altp1) product X 100 30 1000 33
P1 (altp1) product X 100 30 1000 33
P2 (altp2) product Y 10 0 100 9
P2 (altp2) product Y 10 0 100 9
P2 (altp2) product Y 10 0 100 9
P3 (altp3) product Z 30 0 20 1
...
我做错了什么?
前 10 个产品信息在 order_details table 中,但您需要有订单 table 才能根据 orders.shipped_date 进行筛选。
您需要产品 table 来获取产品相关信息和库存 table 来了解当前库存。
所以我将从 order 和 order_details table inner joined 开始,因为在 order_details table.
中没有使用带有 null 的订单
每个订单详细信息都有产品 sku,所以它应该与产品内部连接'
最后我在考虑所有的产品都是库存项目,当我们寻找最畅销的产品时,这些产品必须记录在库存中,这样库存也会被内联。
不确定为什么要在查询中使用产品详细信息。
虽然您在查询中选择了 alt_sku,但它不在您的结果集中。
如果您不需要此 alt_sku 和按月最畅销的产品,查询将如下所示。
DECLARE @FirstDayOfYear AS DATETIME = DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0);
DECLARE @CurrentMonth AS INTEGER = MONTH(GetDate());
SELECT TOP 10
p.sku as product
,p.description as [description]
,SUM(wh.qty) as [in-stock]
,SUM(od.shipped_qty) as YTD
,SUM(CASE WHEN MONTH(o.shipped_date) = @CurrentMonth THEN od.shipped_qty ELSE 0 END) as MTD
,AVG(od.shipped_qty) as [Avg]
FROM
orders as o
INNER JOIN order_details as od on o.order_id = od.order_id
INNER JOIN product as p on od.sku= p.sku
INNER JOIN inventory as wh on wh.sku = p.sku
WHERE o.shipped_date >= @FirstDayOfYear
GROUP BY p.sku, p.description
ORDER by MTD DESC
我修改了查询,现在看起来是这样的。它在 3 秒内加载完毕!
declare @ReportDate as date = GETDATE();
declare @YearStart as date = DATEFROMPARTS(YEAR(@ReportDate), 1, 1);
declare @MonthStart as date = DATEFROMPARTS(YEAR(@ReportDate), MONTH(@ReportDate), 1);
declare @Last6Months as date = DATEADD(mm, -6, @ReportDate)
WITH CTE_Summary (product_id, shipdate, shipped) AS (
SELECT product_id, orders.shipped_date, order_details.shipped_qty FROM order_details
LEFT JOIN orders ON orders.order_id = order_details.order_id
WHERE orders.shipped_date BETWEEN IIF(@YearStart > @Last6Months, @Last6Months, @YearStart) AND @ReportDate
AND orders.shipdate IS NOT NULL
)
SELECT TOP 10
o.product_id
, ytd = (SELECT SUM(shipped) FROM CTE_Summary y where y.sku = o.sku AND y.shipdate >= @YearStart)
, mtd = (SELECT SUM(shipped) FROM CTE_Summary m where m.sku = o.sku AND m.shipdate >= @MonthStart)
, [avg] = (SELECT AVG(shipped) FROM CTE_Summary a where a.sku = o.sku AND a.shipdate>= @Last6Months)
, stock = (SELECT qty FROM inventory wh where wh.sku = o.sku)
FROM CTE_Summary o
GROUP BY o.sku
order by ytd desc
对于库存报告,我需要为最畅销的 10 种产品生成输出
product description in-stock MTD YTD Avg
---------------------------------------------------------------------------
P1 (altp1) product X 100 30 1000 33
P2 (altp2) product Y 10 0 100 9
产品相关表:
- 产品(sku、描述……)
- products_details (sku, altsku, ...)
订单相关表:
- 订单(id,shipped_date,...)
- order_details (id, order_id, product_id, shipped_qty, ....)
仓库库存
- 库存(id,[warehouse_id,product_id,数量,...)
我尝试 SQL 使用连接和子查询,但处理结果花了大约 7 分钟
SELECT TOP 10
p.sku
,p1.alt_sku
,p.description
,wh.qty
,SUM(od.shipped_qty) as YTD
,SUM(od.shipped_qty) as MTD
,AVG(od.shipped_qty) as AvgSales -- how do I get avg of last six months?
FROM product as p
INNER JOIN product_details as p1 ON p.sku = p1.sku
LEFT JOIN inventory as wh on wh.sku = p.sku
LEFT JOIN order_details as od on od.sku= p.sku
LEFT JOIN orders as o on o.order_id = od.order_id
WHERE o.shipped_date >= @YearStart
GROUP BY p.sku, p1.alt_sku, p.description, o.shipped_date, wh.qty, od.shipped_qty
ORDER by MTD DESC
我尝试使用 CTE,它大大加快了查询速度。但是结果出现了重复的skus和double entries
WITH CTE_Summary(product_id, yy, mm, shipped) as (
SELECT
orders.product_id, yy, mm, SUM(orders.shipped_qty) as shipped
FROM (
select o.id
, od.product_id
, SUM(od.shipped_qty) shipped_qty
, year(o.shipped_date) yy
, month(o.shipped_date) mm
from orders o
LEFT JOIN order_details od on od.order_id = o.id
GROUP BY o.id, od.product_id, year(o.shipped_date), month(o.shipped_date)
) AS orders
WHERE orders.yy >= YEAR(GetDate())
GROUP BY orders.product_id, orders.yy, orders.mm
)
SELECT sku.sku, sku.description, sku.alt_sku, sku.instock, summ.avgshipped, summ.YTD, summ.MTD, sku.sku, sku.DESCR, sku.ALTSKU, sku.DESCR, sku.instock
FROM (SELECT top 10 product_id
, AVG(shipped) as avgshipped
, SUM(shipped) as YTD
, SUM(CASE WHEN mm = MONTH(GetDate()) THEN shipped ELSE 0 END) as mtd
from CTE_Summary GROUP BY product_id order by mtd desc, ytd desc) summ
LEFT JOIN (
SELECT p1.sku, p1.description, p2.alt_sku, wh.qty as instock FROM products p1
LEFT JOIN product_details p2 ON p2.product_id = p1.id
LEFT JOIN inventory wh on wh.product_id = p1.id
) sku ON sku.product_id = summ.product_id
但是每个产品 returns 多行(类似这样)
product description in-stock MTD YTD Avg
---------------------------------------------------------------------------
P1 (altp1) product X 100 30 1000 33
P1 (altp1) product X 100 30 1000 33
P2 (altp2) product Y 10 0 100 9
P2 (altp2) product Y 10 0 100 9
P2 (altp2) product Y 10 0 100 9
P3 (altp3) product Z 30 0 20 1
...
我做错了什么?
前 10 个产品信息在 order_details table 中,但您需要有订单 table 才能根据 orders.shipped_date 进行筛选。 您需要产品 table 来获取产品相关信息和库存 table 来了解当前库存。
所以我将从 order 和 order_details table inner joined 开始,因为在 order_details table.
中没有使用带有 null 的订单每个订单详细信息都有产品 sku,所以它应该与产品内部连接' 最后我在考虑所有的产品都是库存项目,当我们寻找最畅销的产品时,这些产品必须记录在库存中,这样库存也会被内联。
不确定为什么要在查询中使用产品详细信息。 虽然您在查询中选择了 alt_sku,但它不在您的结果集中。
如果您不需要此 alt_sku 和按月最畅销的产品,查询将如下所示。
DECLARE @FirstDayOfYear AS DATETIME = DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0);
DECLARE @CurrentMonth AS INTEGER = MONTH(GetDate());
SELECT TOP 10
p.sku as product
,p.description as [description]
,SUM(wh.qty) as [in-stock]
,SUM(od.shipped_qty) as YTD
,SUM(CASE WHEN MONTH(o.shipped_date) = @CurrentMonth THEN od.shipped_qty ELSE 0 END) as MTD
,AVG(od.shipped_qty) as [Avg]
FROM
orders as o
INNER JOIN order_details as od on o.order_id = od.order_id
INNER JOIN product as p on od.sku= p.sku
INNER JOIN inventory as wh on wh.sku = p.sku
WHERE o.shipped_date >= @FirstDayOfYear
GROUP BY p.sku, p.description
ORDER by MTD DESC
我修改了查询,现在看起来是这样的。它在 3 秒内加载完毕!
declare @ReportDate as date = GETDATE();
declare @YearStart as date = DATEFROMPARTS(YEAR(@ReportDate), 1, 1);
declare @MonthStart as date = DATEFROMPARTS(YEAR(@ReportDate), MONTH(@ReportDate), 1);
declare @Last6Months as date = DATEADD(mm, -6, @ReportDate)
WITH CTE_Summary (product_id, shipdate, shipped) AS (
SELECT product_id, orders.shipped_date, order_details.shipped_qty FROM order_details
LEFT JOIN orders ON orders.order_id = order_details.order_id
WHERE orders.shipped_date BETWEEN IIF(@YearStart > @Last6Months, @Last6Months, @YearStart) AND @ReportDate
AND orders.shipdate IS NOT NULL
)
SELECT TOP 10
o.product_id
, ytd = (SELECT SUM(shipped) FROM CTE_Summary y where y.sku = o.sku AND y.shipdate >= @YearStart)
, mtd = (SELECT SUM(shipped) FROM CTE_Summary m where m.sku = o.sku AND m.shipdate >= @MonthStart)
, [avg] = (SELECT AVG(shipped) FROM CTE_Summary a where a.sku = o.sku AND a.shipdate>= @Last6Months)
, stock = (SELECT qty FROM inventory wh where wh.sku = o.sku)
FROM CTE_Summary o
GROUP BY o.sku
order by ytd desc