从嵌套 SQL 查询中选择 TOP 或 GROUP BY 排名数据
Posted
技术标签:
【中文标题】从嵌套 SQL 查询中选择 TOP 或 GROUP BY 排名数据【英文标题】:Select TOP or GROUP BY ranked data from nested SQL query 【发布时间】:2019-11-01 21:07:03 【问题描述】:我有一个包含事件和结果的表格以及如下查询:
SELECT T2.EventDate, T2.EventPlace, T2.Par1,
T2.Par2, T2.Result, T2.ResultEventDate_sum
FROM
(SELECT TOP 15 EventDate, EventPlace, Par1, Par2,
Result, SUM(Result) OVER (PARTITION BY EventDate) AS ResultEventDate_SUM
FROM
(SELECT EventDate, EventPlace, Par1, Par2, Result,
ROW_NUMBER() OVER (PARTITION BY EventDate ORDER BY Result DESC) AS EventDate_rank
FROM MainTable
WHERE AND CAST(UserNb AS int) = 103
AND Col1 = 'X' AND Result > 0 AND Col2 LIKE '%Y%'
AND Par1 > 500 AND Par1 <= 700) ranked
WHERE EventDate_rank <= 5 ORDER BY ResultEventDate_sum DESC) T2
我得到的结果:
EventDate EventPlace Par1 Par2 结果 ResultEventDate_SUM 2019-05-26 地点 nb 1 508 604 51.20 278.11 2019-05-26 地点 nb 1 508 571 51.68 278.11 2019-05-26 地点 nb 1 508 249 56.38 278.11 2019-05-26 地点 nb 1 508 42 59.40 278.11 2019-05-26 地点 nb 1 508 39 59.45 278.11 2019-06-09 地点 nb 3 508 449 50.95 217.05 2019-06-09 地点 nb 3 508 259 54.79 217.05 2019-06-09 地点 nb 3 508 254 54.89 217.05 2019-06-09 地点 nb 3 508 178 56.42 217.05 2019-06-16 地点 nb 4 508 372 51.49 169.56 2019-06-16 地点 nb 4 508 66 58.51 169.56 2019-06-16 地点 nb 4 508 20 59.56 169.56 2019-06-02 地点 nb 2 508 533 50.19 107.46 2019-06-02 地点 nb 2 508 149 57.27 107.46我需要从每个事件中获取最多 5 个结果的最佳(最高)总和列表,但只选择 3 个最佳事件。所以我放了 SELECT TOP 15(5 个结果的 3 个事件),当每个事件有 5 个结果时,查询结果就可以了。但是,如果每个事件的结果少于 5 个,我也会从 4 个事件中获得记录。如何修改查询以确保无论每个事件有多少结果,都只有 3 个事件?在此示例中,剪切最后 2 条记录(1 个事件的最小结果为 107.46)。有没有办法通过简化查询而不添加其他代码来实现这一点?
我尝试将 COUNT(*) 放在第一行,但它的计数与 col resulteventdate 相同,因此我不能将其用作条件。另外,如果我添加了前任。 EXISTS,语句太大,需要很长时间。
预期结果是一个只有 3 个事件的表,其中 ResultEventDate_sum 最好:
EventDate EventPlace Par1 Par2 结果 ResultEventDate_SUM 2019-05-26 地点 nb 1 508 604 51.20 278.11 2019-05-26 地点 nb 1 508 571 51.68 278.11 2019-05-26 地点 nb 1 508 249 56.38 278.11 2019-05-26 地点 nb 1 508 42 59.40 278.11 2019-05-26 地点 nb 1 508 39 59.45 278.11 2019-06-09 地点 nb 3 508 449 50.95 217.05 2019-06-09 地点 nb 3 508 259 54.79 217.05 2019-06-09 地点 nb 3 508 254 54.89 217.05 2019-06-09 地点 nb 3 508 178 56.42 217.05 2019-06-16 地点 nb 4 508 372 51.49 169.56 2019-06-16 地点 nb 4 508 66 58.51 169.56 2019-06-16 地点 nb 4 508 20 59.56 169.56提前感谢您的任何提示。
测试后更新: 感谢大家。我在查询中测试了您的命题,Dense_Rank 正确且非常快地完成了这项工作。对我帮助很大。
【问题讨论】:
您真的在使用 SQL Server 2005 吗? 是的,还是 2005 年 那你真的应该考虑升级了。 2008 版即将停止扩展支持。 2005已经很久不支持了…… 计划就是这样。我不能在赛季期间参加这些活动,也许当它结束时。 如何区分事件和你显示的结果集?我的意思是有任何Event_Id吗?另外请在问题中添加您的预期输出。这会有所帮助。 【参考方案1】:您需要再使用一个窗口函数,即 Dense_Rank。 这可能会帮助您获得所需的输出。
select EventDate,EventPlace,Par1,Par2,Result,ResultEventDate_sum from(
SELECT T2.EventDate, T2.EventPlace, T2.Par1,
T2.Par2, T2.Result, T2.ResultEventDate_sum ,
DENSE_RANK()over(order by ResultEventDate_sum,T2.EventDate desc)rnk
FROM
(SELECT EventDate, EventPlace, Par1, Par2,
Result, SUM(Result) OVER (PARTITION BY EventDate) AS ResultEventDate_SUM
FROM
(SELECT EventDate, EventPlace, Par1, Par2, Result,
ROW_NUMBER() OVER (PARTITION BY EventDate ORDER BY Result DESC) AS
EventDate_rank
FROM MainTable
WHERE AND CAST(UserNb AS int) = 103
AND Col1 = 'X' AND Result > 0 AND Col2 LIKE '%Y%'
AND Par1 > 500 AND Par1 <= 700) ranked
WHERE EventDate_rank <= 5 ) T2
)T1
WHERE RNK<=3
【讨论】:
【参考方案2】:在以下查询中,我将 EventPlace 视为 Event_ID。此查询将返回前 3 个事件(基于每个事件结果的总和)详细信息(每个事件的前 5 行)
SELECT * FROM
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY EventPlace ORDER BY EventPlace,Result DESC) RN
FROM your_table
WHERE EventPlace IN
(
-- You can set any number based on
-- How many event details you wants to see
SELECT TOP 3 EventPlace
FROM
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY EventPlace ORDER BY EventPlace,Result DESC) RN
FROM your_table
)A
-- You can set any number based on
-- How many row's result you want to SUM for checking
WHERE RN <= 5
GROUP BY EventPlace
ORDER BY SUM(Result) DESC
)
)B
WHERE RN <= 5
【讨论】:
感谢您的回答。我做了一些测试,第一个使用 Dense_Rank 的解决方案更快,所以我使用了那个。您的提议非常灵活,所以我很遗憾,我没有选择将两个答案设置为解决方案。非常感谢。以上是关于从嵌套 SQL 查询中选择 TOP 或 GROUP BY 排名数据的主要内容,如果未能解决你的问题,请参考以下文章
EF Core 嵌套 Linq 选择导致 N + 1 个 SQL 查询