SQL复合密钥分组问题
我遇到了一个非常令人沮丧的SQL问题,我无法用一个派生查询来解决这个问题,该查询返回一个复合键,但同时对该表中的另一个字段执行最小聚合函数。如果我在其中一个组合键上执行MIN,这将很容易,但是由于我需要返回两个键并对外部查询执行MIN函数,所以我无法确定如何执行此操作。整个查询如下所示:SQL复合密钥分组问题,sql,group-by,composite-key,unique-constraint,Sql,Group By,Composite Key,Unique Constraint,我遇到了一个非常令人沮丧的SQL问题,我无法用一个派生查询来解决这个问题,该查询返回一个复合键,但同时对该表中的另一个字段执行最小聚合函数。如果我在其中一个组合键上执行MIN,这将很容易,但是由于我需要返回两个键并对外部查询执行MIN函数,所以我无法确定如何执行此操作。整个查询如下所示: SELECT p.name as productname ,tmp.packageid ,tmp.price ,ppk2.packageoptionid ,ppk2.selcom
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是我的问题所在,因为在加入外部表之前,我需要为每个价格最低的产品/包组合返回唯一的行
任何帮助都将不胜感激 易读:昂贵的方法:构建两个视图:一个视图只获取每个productid的最低ppk.price,其中pk.networkid=1,另一个视图按productid分组。称之为“产品”\u MinPrice\u VIEW或其他任何名称 构建第二个视图“产品”视图,该视图将替换您试图通过对刚刚创建的“产品”视图的结果进行内部联接而摆脱的所有子选择内部联接工作 我发誓,与次级选择、HAVINGS和GROUP BY的争论是乏味且容易出错的。我有时受不了。希望,这将使您能够开发出一个解决方案,以后可以对其进行优化并使其更加正确 最终答案 对于我正在开发的应用程序,在我访问这个网站寻找更好答案的同时,我只是推卸责任,编写了一些应用程序级代码来处理任何重复项,并让程序的逻辑在遇到问题时找到真正的最小值。不漂亮,但我又没有一整天的时间去想它
很抱歉,我的回答帮不了你。祝你好运 易读:昂贵的方法:构建两个视图:一个视图只获取每个productid的最低ppk.price,其中pk.networkid=1,另一个视图按productid分组。称之为“产品”\u MinPrice\u VIEW或其他任何名称 构建第二个视图“产品”视图,该视图将替换您试图通过对刚刚创建的“产品”视图的结果进行内部联接而摆脱的所有子选择内部联接工作 我发誓,与次级选择、HAVINGS和GROUP BY的争论是乏味且容易出错的。我有时受不了。希望,这将使您能够开发出一个解决方案,以后可以对其进行优化并使其更加正确 最终答案 对于我正在开发的应用程序,在我访问这个网站寻找更好答案的同时,我只是推卸责任,编写了一些应用程序级代码来处理任何重复项,并让程序的逻辑在遇到问题时找到真正的最小值。不漂亮,但我又没有一整天的时间去想它
很抱歉,我的回答帮不了你。祝你好运 每当我需要子查询和最小的查询时,我都会使用这个技巧。其思想是将值和键与最高有效位中的值组合在一起,并取其最小值。然后在外部选择中将其拆下 组合到值的最佳方式取决于您使用的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
每当我需要子查询和最小的查询时,我都会使用这个技巧。其思想是将值和键与最高有效位中的值组合在一起,并取其最小值。然后在外部选择中将其拆下 组合到值的最佳方式取决于您使用的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
我不知道你桌上的数据。我只有你查询返回的数据。您没有回答我的评论,我要求您提供表的数据样本以及您正在使用的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
在table words中,查询将以下内容转换为:
+-----------+-----------+---------+
| 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 |
+-----------+-----------+---------+
请告诉我是否清楚。嗯,我不知道您表中的实际数据。我只有你查询返回的数据。您没有回答我的评论,我要求您提供表的数据样本以及您正在使用的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
在table words中,查询将以下内容转换为:
+-----------+-----------+---------+
| 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 |
+-----------+-----------+---------+
请告诉我是否清楚。问得好。现在:您可以注册一个,这样我们就不必看stackoverflow在您的代码周围放置的那些丑陋的滑块了吗@Droogans或者你可以格式化代码…@ninesided:touch,好先生。@Droogans:我不知道你的情况,但我跳过了任何涉及pastebin帐户的问题。谢谢你编辑Nines
我想,我不应该考虑更低的决议对不起,问得好。现在:您可以注册一个,这样我们就不必看stackoverflow在您的代码周围放置的那些丑陋的滑块了吗@Droogans或者你可以格式化代码…@ninesided:Touche,好先生。@Droogans:我不知道你的情况,但我跳过任何涉及pastebin帐户的问题。谢谢你编辑ninesided,我不应该考虑更低的分辨率。对不起。嗨,Droogan,谢谢你的回复。好吧,问题不是最低包装ID,而是影响行的最低价格。因此,如果一个产品有多个包装,那么只返回价格最低的包装。但关键是我需要返回productid/packageid,以便将唯一的连接返回到该表以获取进一步的数据。我同意分组和子选择是痛苦的,特别是当需要返回多个列到树上,并且涉及多个聚合函数时:SAh,我会更新我的答案,但我可以看到您的问题所在。我的解决方案是完全删除packageid,这可能会混淆真实答案的数据。我必须对此进行更多的研究。是的,这正是我们遇到的问题,Droggans,我们可以删掉packageid,并愉快地获得productid和最低价格,但随后我们失去了链接回该表以访问进一步数据的能力。最初我会把所有数据都带回来,但MINprice和GroupBy不可能这样做,我甚至尝试了3个级别的派生查询,但都没有成功。我也从来没有真正找到解决这类问题的好办法,因为我记得过去曾遇到过类似的问题;当productid 1,packageid 500的价格为0.0,productid 1,packageid 501的价格也为0.0时,会发生什么情况?你会说什么,然后接受packageid 500吗?如果它有帮助,Product_Package表如下所示:Product_Package[id,productid,packageid,PackagePartitionID,price,selcomproductid,listorder]id-CMS productid所需的标识字段和主键| packageid-唯一性约束Thi Droogan感谢您的回复。好吧,问题不是最低包装ID,而是影响行的最低价格。因此,如果一个产品有多个包装,那么只返回价格最低的包装。但关键是我需要返回productid/packageid,以便将唯一的连接返回到该表以获取进一步的数据。我同意分组和子选择是痛苦的,特别是当需要返回多个列到树上,并且涉及多个聚合函数时:SAh,我会更新我的答案,但我可以看到您的问题所在。我的解决方案是完全删除packageid,这可能会混淆真实答案的数据。我必须对此进行更多的研究。是的,这正是我们遇到的问题,Droggans,我们可以删掉packageid,并愉快地获得productid和最低价格,但随后我们失去了链接回该表以访问进一步数据的能力。最初我会把所有数据都带回来,但MINprice和GroupBy不可能这样做,我甚至尝试了3个级别的派生查询,但都没有成功。我也从来没有真正找到解决这类问题的好办法,因为我记得过去曾遇到过类似的问题;当productid 1,packageid 500的价格为0.0,productid 1,packageid 501的价格也为0.0时,会发生什么情况?你会说什么,然后拿packageid 500吗?如果有帮助,Product\u Package表如下所示:Product\u Package[id,productid,packageid,PackagePartitionID,price,selcomproductid,listorder]CMS productid | packageid-university constraintThanks Mosty所需的id-IDENTITY字段和主键这是实现MIN函数的一种有趣的方式,它似乎确实起作用,尽管它显然要冗长得多,但它确实为我提供了任何特定字段中最低的字段。我想SQL Server中没有一种解决方案能够在需要返回复合键时返回多个值和最小聚合。谢谢你的帮助!感谢Mosty,这是一种实现MIN函数的有趣方法,它似乎确实有效,尽管它显然要冗长得多,但它确实为我提供了任何特定领域中最低的。我想SQL Server中没有一种解决方案能够在需要返回复合键时返回多个值和最小聚合。谢谢你的帮助!谢谢Gordy,这是另一个有趣的答案,我也尝试过类似的方法,将价格和包装组合在一起,但它实在太难看了。你的方法更优雅,我没有想到在这种情况下使用数学。@PhilRasmussen:我想这取决于你如何衡量一个查询的丑陋程度?我建议将此方法的执行计划与您接受的答案中的执行计划进行比较。如果你
如果你真的想改进它,你可以为Min编写一个用户定义的聚合,它包含两个参数。谢谢Gordy,这是另一个有趣的答案,我也尝试过类似的方法,将price和packageid组合到Min中,但它实在太难看了。你的方法更优雅,我没有想到在这种情况下使用数学。@PhilRasmussen:我想这取决于你如何衡量一个查询的丑陋程度?我建议将此方法的执行计划与您接受的答案中的执行计划进行比较。如果您真的想改进它,您可以为Min编写一个用户定义的聚合,该聚合包含两个参数。