Mysql 为库存项目从多个供应商中选择最近的最低价格
我相当精通SQL,但是这个问题已经困扰了我好一阵子了。从最基本的意义上讲,只有两个表:Mysql 为库存项目从多个供应商中选择最近的最低价格,mysql,sql,postgresql,greatest-n-per-group,distinct-on,Mysql,Sql,Postgresql,Greatest N Per Group,Distinct On,我相当精通SQL,但是这个问题已经困扰了我好一阵子了。从最基本的意义上讲,只有两个表: Items +----+--------+ | id | title | +----+--------+ | 1 | socks | | 2 | banana | | 3 | watch | | 4 | box | | 5 | shoe | +----+--------+ …以及价格表: Prices +---------+-----------+-------+---------
Items
+----+--------+
| id | title |
+----+--------+
| 1 | socks |
| 2 | banana |
| 3 | watch |
| 4 | box |
| 5 | shoe |
+----+--------+
…以及价格表:
Prices
+---------+-----------+-------+------------+
| item_id | vendor_id | price | created_at |
+---------+-----------+-------+------------+
| 1 | 1 | 5.99 | Today |
| 1 | 2 | 4.99 | Today |
| 2 | 1 | 6.99 | Today |
| 2 | 2 | 6.99 | Today |
| 1 | 1 | 3.99 | Yesterday |
| 1 | 1 | 4.99 | Yesterday |
| 2 | 1 | 6.99 | Yesterday |
| 2 | 2 | 6.99 | Yesterday |
+---------+-----------+-------+------------+
请注意:创建时间实际上是一个时间戳,提供“今天”和“昨天”只是为了快速传达概念
我的目标是返回一个简单的结果,其中包含与最新最低价格关联的库存项目,包括对提供所述价格的供应商id的引用
然而,我发现阻碍因素似乎是一个或多个语句需要处理的需求数量:
每个项目都有多个供应商,因此我们需要确定每个项目的所有供应商之间的价格最低
项目的新价格定期被追加,因此我们只考虑每个供应商的每个项目的最新价格。
我们希望将所有这些汇总到一个结果中,每行一个项目,包括项目、价格和供应商
这看起来很简单,但我发现这个问题异常困难
请注意,我使用的是Postgres,因此它提供的所有功能都可以使用,例如:窗口功能。试试这个
CREATE TABLE #Prices ( Iid INT, Vid INT, Price Money, Created DateTime)
INSERT INTO #Prices
SELECT 1, 1, 5.99 ,GETDATE() UNION
SELECT 1, 2, 4.99 ,GETDATE() UNION
SELECT 2, 1, 6.99 ,GETDATE() UNION
SELECT 2, 2, 6.99 ,GETDATE() UNION
SELECT 1, 1, 3.99 ,GETDATE()-1 UNION
SELECT 1, 2, 4.99 ,GETDATE()-1 UNION
SELECT 2, 1, 6.99 ,GETDATE()-1 UNION
SELECT 2, 2, 6.99 ,GETDATE()-1
WITH CTE AS
(
SELECT
MyPriority = ROW_NUMBER() OVER ( partition by Iid, Vid ORDER BY Created DESC, Price ASC)
, Iid
, Vid
, price
, Created
FROM #Prices
)
SELECT * FROM CTE WHERE MyPriority = 1
试试这个
CREATE TABLE #Prices ( Iid INT, Vid INT, Price Money, Created DateTime)
INSERT INTO #Prices
SELECT 1, 1, 5.99 ,GETDATE() UNION
SELECT 1, 2, 4.99 ,GETDATE() UNION
SELECT 2, 1, 6.99 ,GETDATE() UNION
SELECT 2, 2, 6.99 ,GETDATE() UNION
SELECT 1, 1, 3.99 ,GETDATE()-1 UNION
SELECT 1, 2, 4.99 ,GETDATE()-1 UNION
SELECT 2, 1, 6.99 ,GETDATE()-1 UNION
SELECT 2, 2, 6.99 ,GETDATE()-1
WITH CTE AS
(
SELECT
MyPriority = ROW_NUMBER() OVER ( partition by Iid, Vid ORDER BY Created DESC, Price ASC)
, Iid
, Vid
, price
, Created
FROM #Prices
)
SELECT * FROM CTE WHERE MyPriority = 1
在Postgres中使用DISTINCT ON更简单:
每个供应商的每项当前价格
每个项目的最佳供应商
详细说明:
在Postgres中使用DISTINCT ON更简单:
每个供应商的每项当前价格
每个项目的最佳供应商
详细说明:
也可以使用窗口函数执行此操作,它将在SQL Server version>2005上运行:
with cte1 as (
select
*,
row_number() over(partition by vendor_id, item_id order by created_at desc) as row_num
from prices
), cte2 as (
select
*,
row_number() over(partition by item_id order by price asc) as row_num2
from cte1
where row_num = 1
)
select i.title, c.price, c.vendor_id
from cte2 as c
inner join items as i on i.id = c.item_id
where c.row_num2 = 1;
感谢Erwin,也可以使用窗口函数执行此操作,它将在SQL Server version>2005上运行:
with cte1 as (
select
*,
row_number() over(partition by vendor_id, item_id order by created_at desc) as row_num
from prices
), cte2 as (
select
*,
row_number() over(partition by item_id order by price asc) as row_num2
from cte1
where row_num = 1
)
select i.title, c.price, c.vendor_id
from cte2 as c
inner join items as i on i.id = c.item_id
where c.row_num2 = 1;
感谢Erwin非常接近-但是,这会导致为每个供应商id返回一个项目id。将其归结为单个项目id的最佳方法是什么?非常接近-但是,这将导致为每个供应商返回一个商品标识。将其还原为单个商品标识的最佳方式是什么?您认为最近的最低价格是什么意思?你想要最低的价格吗?还是最近的?或者两者的某种结合?@GordonLinoff:进一步的解释澄清了这一点。你说的最近的最低价格是什么意思?你想要最低的价格吗?还是最近的?还是两者的某种结合?@GordonLinoff:进一步解释清楚了这一点。这显示了每个供应商的当前价格。我相信OP还想知道每个项目的最佳供应商。这可以通过将答案转换成子查询,然后按价格从子查询顺序中选择不同的ONitem\u id*来实现,是吗?OMG SQLFIDLE是一个东西!不管怎样,安德鲁是对的,我不想要袜子的多个结果,每个项目只有一个结果。@AndrewLazarus:对,第二步不见了。他补充道。不过,ORDER BY需要与DISTINCT ON匹配。所以我们需要按商品编号、价格订购。@ErwinBrandstetter:甚至荷马点头。这显示了每个供应商的当前价格。我相信OP还想知道每个项目的最佳供应商。这可以通过将答案转换成子查询,然后按价格从子查询顺序中选择不同的ONitem\u id*来实现,是吗?OMG SQLFIDLE是一个东西!不管怎样,安德鲁是对的,我不想要袜子的多个结果,每个项目只有一个结果。@AndrewLazarus:对,第二步不见了。他补充道。不过,ORDER BY需要与DISTINCT ON匹配。所以我们需要按商品编号、价格订购。@ErwinBrandstetter:连荷马也点头。