我有一个非常令人沮丧的SQL问题,我不能为我的生活解决一个派生查询返回一个复合键,但也在该表中的另一个字段上执行MIN()聚合函数。如果我在其中一个复合键上执行MIN()它会很容易,但由于我需要返回两个键并执行MIN()函数以及外部查询我无法解决如何执行此操作。整个查询如下所示:
SELECT
p.name as productname
,tmp.packageid
,tmp.price
,ppk2.packageoptionid
,ppk2.selcomproductid
FROM (
SELECT ppk.productid, ppk.packageid, MIN(ppk.price) as price
FROM product_package ppk
INNER JOIN package pk ON ppk.packageid = pk.id
INNER JOIN [plan] pl ON pk.planid = pl.id
WHERE pk.networkid = 1
GROUP BY ppk.productid, ppk.packageid
) tmp
INNER JOIN product_package ppk2 ON (
ppk2.productid = tmp.productid
AND ppk2.packageid = tmp.packageid
)
INNER JOIN product p ON (p.id = ppk2.productid)
WHERE p.isenabled = 1;
当前结果:
--------------------------------------
productid | packageid | price
1 500 0
1 501 19.95
1 502 29.95
2 501 0
3 500 15
3 504 39.95
期望的结果:
--------------------------------------
productid | packageid | price
1 500 0
2 501 0
3 500 15
派生查询“tmp”是我的问题所在,因为在加入外部表之前,我需要为每个具有最低价格的产品/包组合返回唯一的行。
非常感谢任何帮助!
答案 0 :(得分:2)
每当我需要子查询以及最小的东西时,我就会使用这个技巧。我们的想法是将值和键与最高有效位中的值组合在一起并取其最小值。然后在外部选择中分开。
组合值的最佳方式取决于您使用的RDBMS。你没有提到你正在使用哪一个,所以我只提供伪代码:
select ..., (tmp.c >> 32) price
from
(select productid, min((price << 32) | packageid) c
from product_package
where networkid=1
group by productid) tmp
inner join product_package ppk on ppk.productid=tmp.productid
and ppk.packageid=(tmp.c & 0xFFFFFFFF)
inner join product p on p.id=ppk.productid
where p.isenabled=1
<< 32
表示将值向左移位32位,|
为按位“或”。所以这假设packageid被定义为32位整数(或数字(4))。 & 0xFFFFFFFF
是按位“和”,32位的十六进制值用于屏蔽并返回packageid。
根据您的RDBMS,您可能需要找到这些内容的特定语法,或者如果它们不受支持,您可以使用简单数学 - << 32
相当于乘以4294967296和& 0xFFFFFFFF
除以4294967296。如果您使用的是MSSQL,可以使用convert(binary,price)+convert(binary,packageid)
将它们和substring(..)
合并分开。
答案 1 :(得分:1)
简单(阅读:昂贵)方式:构建两个视图:一个只获得每个ppk.price
的最小productid WHERE pk.networkid = 1
,并按productid
分组。称之为Product_MinPrice_VIEW
或其他。
构建第二个视图Product_VIEW
,用SELECT INNER JOIN
替换INNER JOIN
的所有子Product_MinPrice_VIEW
工作,通过SELECTS
替换HAVINGS
你刚才做的。
我发誓,与子GROUP-BY
,{{1}}和{{1}}争吵是单调乏味且容易出错的。我有时候无法忍受。希望这将使您足够开发一个可以在以后优化并使其更加正确的解决方案。
I have an extremely similar problem使用我正在处理的应用程序,同时(当我点击这个网站以获得更好的答案时),我刚刚推卸责任,并编写了一些应用程序级代码来处理任何重复项,让程序的逻辑在遇到时找到真正的最小值。不漂亮,但是我又没有一整天都想弄明白了!
对不起,我的回答无法帮到你。祝你好运!
答案 2 :(得分:1)
好吧,我不知道你实际拥有的数据。我只有你的查询返回的数据。您没有回答我的评论,要求提供您的表格和您正在使用的DBMS的数据样本。
但是,假设您的表的当前数据是您的查询中的数据,以下查询将为您提供您指定的“所需结果”:
select t1.* from t t1
left join t t2
on t1.productid = t2.productid and t1.details > t2.details
where t2.details is null
在表格中,查询转为:
+-----------+-----------+---------+
| PRODUCTID | PACKAGEID | DETAILS |
+-----------+-----------+---------+
| 1 | 500 | 0 |
| 1 | 501 | 20 |
| 1 | 502 | 30 |
| 2 | 501 | 0 |
| 3 | 500 | 15 |
| 3 | 504 | 40 |
+-----------+-----------+---------+
进入这个:
+-----------+-----------+---------+
| PRODUCTID | PACKAGEID | DETAILS |
+-----------+-----------+---------+
| 1 | 500 | 0 |
| 2 | 501 | 0 |
| 3 | 500 | 15 |
+-----------+-----------+---------+
让我知道是否清楚。