从嵌套 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 排名数据的主要内容,如果未能解决你的问题,请参考以下文章

嵌套选择语句的 SQL GROUP BY

EF Core 嵌套 Linq 选择导致 N + 1 个 SQL 查询

从 Oracle 9i 中的嵌套查询中选择

如何优化执行嵌套在 group-by 子句中的计数的 SQL 查询?

SQL Server 之 子查询与嵌套查询

使用嵌套查询从表列表/多个表中选择 - MS SQL