按非主键属性分组 min(Value) 并从同一行加入附加属性(使用原始 SQL 或 SQLalchemy)
Posted
技术标签:
【中文标题】按非主键属性分组 min(Value) 并从同一行加入附加属性(使用原始 SQL 或 SQLalchemy)【英文标题】:Group min(Value) by non-primary key-attribute and join additional attribute from the same row (with raw SQL or SQLalchemy) 【发布时间】:2018-05-12 23:54:02 【问题描述】:鉴于我有下表“PriceRecord”:
| PriceRecord_ID | Company_ID | Price | Tarif_type | Tarif_Model | ... attributes |
|:--------------:|:----------:|:-----:|:----------:|:----------:|:--------------:|
| 1 | A | 10 | tarif_1 | Model_1 | ... |
| 2 | A | 20 | tarif_2 | Model_1 | ... |
| 3 | A | 10 | tarif_3 | Model_2 | ... |
| 4 | B | 11 | tarif_1 | Model_2 | ... |
| 5 | B | 15 | tarif_2 | Model_3 | ... |
| 6 | C | 10 | tarif_1 | Model_4 | ... |
我的目标是获得每家公司的最低(价格)。对于每个 min(Price),我还需要其他属性(例如 Tarif_type、Tarif_name)。
预期结果:
| PriceRecord_ID | Company_ID | Price | Tarif_type | Tarif_Model | ... attributes |
|:--------------:|:----------:|:-----:|:----------:|:----------:|:--------------:|
| 1 | A | 10 | tarif_1 | Model_1 | ... |
| 4 | B | 11 | tarif_1 | Model_1 | ... |
| 6 | C | 10 | tarif_1 | Model_2 |
我知道如何按公司获取最低(价格)和分组。我的问题是,我无法加入其他属性(因为公司名称不是唯一键。
我尝试了这个查询(如果两个条件都满足,则打算加入该表 --> 不幸的是,它为每个条件加入了两次,并且我的结果表中每个公司都有多个记录)
subquery = db.session.query(PriceRecord.company_id, db.func.min(PriceRecord.Price).label("minPrice")) \
.group_by(PriceRecord.company_id) \
.subquery()
result = db.session.query(subquery.c.company_id, subquery.c.minPrice, PriceRecord.tarif_type, PriceRecord.tarif_model) \
.join(PriceRecord, subquery.c.insurance_company==PriceRecord.company_id and subquery.c.minPrice==PriceRecord.Price) \
我找到了 this 类似的解决方案,但无法针对我的场景实施。
非常感谢任何帮助!提前谢谢你
【问题讨论】:
您没有清楚地使用“公司”。您似乎在说公司列实际上是公司名称。如果公司名称不是唯一的,您怎么可能获得每个公司的信息?您只能获取每个公司名称的信息。您需要在名称旁边附上公司 ID。 感谢您的意见。我澄清了上面的描述。公司是另一个表的外键。但我的问题是,一家公司可以有多个具有相同最小值(价格)的价格记录。在这种情况下,只希望一个记录显示在我的结果表中(哪个记录并不重要,例如找到的第一个或最容易实现的记录)。该表有 250k 的价格记录,否则它会很快变得混乱。谢谢你的时间 【参考方案1】:SELECT b.*
FROM (
SELECT Company, MIN(Price) Price FROM PriceRecord GROUP BY Company
) a
JOIN PriceRecord b on a.Company = b.Company and a.Price = b.Price
一个警告 - 如果 A 公司有两行价格为 10,则两者都将返回。
【讨论】:
您的解决方案是正确的,但不幸的是,大多数公司都有多个价格相同的价格记录 -> 这就是我的结果表中有多个条目的原因。是否有可能只获得每家公司的 min(Price) 第一行? @Simon “第一”是什么意思?首先是什么时候订购的?无论如何,这里没有每个公司,只有每个公司。 找到的 min(Prices) 中的哪一个以及相应的属性显示在结果表中并不重要。以最容易实现的为准。非常感谢您的帮助 将 SELECT 更改为:SELECT DISTINCT b.Company, b.Price 这将使您每家公司只有一行,并且该公司的最低价格。【参考方案2】:经过一番研究,我能够使用以下 sql 代码得到预期的结果:
select *
from
(
select
row_number () over (partition by company_ID order by premium asc) as rownumber,
min(Price) over (partition by company_ID) as minimalPrice, *
FROM price_table
) subquery
where subquery.rownumber = 1
使用所谓的窗口函数,您可以在没有 group_by 语句的情况下使用聚合函数。 rownumber 函数为每个价格记录分配一个“动态”创建的编号(由于分区函数,每个公司的 rownumber 再次从 1 开始)。因为我需要按 rownumber = 1 过滤的每家公司的确切结果。
这里是我的内部选择的示例(没有过滤 rownumber 等于 = 1)
rownumber minprice company_id price
1 408.9 8 408.9
2 408.9 8 436.1
3 408.9 8 439.7
4 408.9 8 463.1
5 408.9 8 468.9
6 408.9 8 490.3
7 408.9 8 498
8 408.9 8 517.5
9 408.9 8 527.2
10 408.9 8 528.2
11 408.9 8 556.4
12 408.9 8 568
1 364.4 32 364.4
2 364.4 32 387.6
3 364.4 32 391.8
4 364.4 32 416.8
5 364.4 32 419.3
6 364.4 32 446
7 364.4 32 446.6
8 364.4 32 474.1
9 364.4 32 475.1
10 364.4 32 485
11 364.4 32 504.3
12 364.4 32 515.9
1 412 57 412
2 412 57 433.7
3 412 57 439.7
我希望这会有所帮助,我花了一些时间来研究那些 sql 函数。
【讨论】:
以上是关于按非主键属性分组 min(Value) 并从同一行加入附加属性(使用原始 SQL 或 SQLalchemy)的主要内容,如果未能解决你的问题,请参考以下文章