【问题标题】:SQL Server query grouped by max value in columnSQL Server 查询按列中的最大值分组
【发布时间】:2009-05-26 00:33:04
【问题描述】:

****更新:**

使用 MS SQL Server 2005 中可用的 Rank() over partition 语法确实为我指明了正确的方向,它(或者我应该写“I”)无法给我需要的结果求助于枚举代码中的行。

例如,如果我们选择 TOP (1) of rank,我只会得到一个值,即 slot 1。如果我使用 MAX(),那么我会得到每个 slot 的 top rank 值。 .在我的情况下,它不起作用,因为如果插槽 2 的顶部值为 NULL,但它旁边的 MAX 值是非空的,那就是我想要的。

因此,无法找到完整的 T-SQL 解决方案,我只好在 SQL 中尽可能多地进行过滤,然后在客户端的代码中枚举结果。

原文:

我一直在访问advanced T-SQL books、StackOverflow 和 google,试图弄清楚如何使用数据透视或使用分析函数来处理此查询。到目前为止,我还没有找到正确的组合。

我有排序的时间表(更高的价值,更大的优先级)。每个时间表都有一个播放列表,其中包含一定数量的带有文件的编号插槽。

我需要做的,是将所有时间表及其关联的播放列表排列起来,并为每个时段,从时间表中获取具有最高排名值的文件。

所以,如果我有一个特定客户的查询,其中播放列表和时间表之间有连接,按 Schedule.Rank DESC 排序,如下所示:

PlaylistId   Schedule.Rank    SlotNumber    FileId
100               100             1          1001
100               100             2          NULL
100               100             3          NULL
200                80             1          1101
200                80             2          NULL 
200                80             3          NULL
300                60             1          1201
300                60             2          NULL
300                60             3          2202
400                20             1          1301
400                20             2          2301
400                20             3          NULL

由此,我需要找到每个 slotnumber 的 MAX 排行的 FileId:

SlotNumber   FileId    Schedule.Rank
1             1001         100
2             2301          20
3             2202          60

关于如何做到这一点的任何想法?

下表定义:

CREATE TABLE dbo.Playlists(
    id int NOT NULL)

CREATE TABLE dbo.Customers(
    id int NOT NULL,
    name nchar(10) NULL)

CREATE TABLE dbo.Schedules(
    id int NOT NULL,
    rank int NOT NULL,
    playlistid int NULL,
    customerid int NULL)

CREATE TABLE dbo.PlaylistSlots(
    id int NOT NULL,
    slotnumber int NOT NULL,
    playlistid int NULL,
    fileid int NULL)

【问题讨论】:

  • +1 只是因为很高兴偶尔看到一个正确提出的问题,以及所有相关的表格和所有 -- 谢谢!!!-)
  • 顺便说一句,pivot 与它没有多大关系(这是关于“翻转”事物,因此行值变成列)所以我正在相应地进行编辑。
  • 我不确定您所指的书是否好。试试这些:sql.co.il

标签: sql sql-server-2005 tsql sql-server-2008


【解决方案1】:
SELECT slotnumber, fileid, rank
FROM
(
    SELECT slotnumber, fileid, Schedules.rank, RANK() OVER (PARTITION BY slotnumber ORDER BY Schedules.rank DESC) as rankfunc
    FROM Schedules
    INNER JOIN PlaylistSlots ON Schedules.playlistid = PlaylistSlots.playlistid
) tmp
WHERE rankfunc = 1

【讨论】:

  • 虽然这个答案并不完全正确(标准中的窗口函数会引发错误),但这个答案的根源让我得到了我的特定于实现的答案。
  • 所以请您发布完全正确的版本(或告诉我如何编辑我的)?正如我在对@mitch 的回答的评论中提到的那样,我无法对此进行测试,所以一些(希望是轻微的!-)错误很可能已经潜入 - 谢谢!
  • 仍在研究解决方案,但为了解决窗口函数问题,您可以将整个选择包装在派生表中。我仍然没有得到我需要的结果,但我正朝着正确的方向前进。当我有一个可行的解决方案时,我会用完整的答案编辑原始问题。
  • 如果您改为使用 rankFunc,它会解决 NULL 问题 ROW_NUMBER() OVER(PARTITION BY slotnumber ORDER BY CASE WHEN FileID IS NULL 1 ELSE 0 END ASC, Schedules.rank DESC)
【解决方案2】:

您是否查看过 SQL Server(2005 年以后)的PARTITION and RANK 功能?

【讨论】:

  • 我已经阅读了关于 SO 和 MSDN 文档的内容....但目前无法成功使用它们。
  • 它们非常适合您所说的问题。
  • 是的 - 我正忙着为基于分区的解决方案键入简洁的代码,即使你的答案已经到来,@Mitch(希望是对的,没有时间测试,抱歉)。所以,作为一个一般性的 SO 问题,什么是最好的 - 像你一样教托德钓鱼,或者像我一样尝试给他一条鱼?不是一个修辞问题,我在这里很新,并试图通过看看老前辈的做法来学习 SO 的风格,但似乎这两种方法都很受欢迎 - 任何反馈都可以发送!
  • @Alex,您的回答为我指明了正确的方向。非常感谢。为了简洁起见,我在 SO 上的帖子非常简单,因此虽然您的回答对于简单的示例可能是正确的,但我至少有一个完成解决方案的方向。
  • @Todd,您的 SO 问题非常完美——突出了需要做出回应的所有方面,并省略了不相关的内容;埃里克雷蒙德会为你感到骄傲。 @Mitch 的回答也很棒,他指向的网址也非常有用。
【解决方案3】:
select SlotNumber, FileId, ScheduleRank FROM intermediateTable a, ( SELECT SlotNumber, Max(Schedule.Rank) as MaxRank FROM intermediateTable O WHERE FileId is not null GROUP BY SlotNumber) b WHERE b.SlotNumber = a.SlotNumber and b.MaxRank = a.Rank

此查询使用中间输出来构建最终输出。
这有帮助吗?

【讨论】:

  • 恕我直言,展示可移植到其他 SQL 引擎而没有排名和分区功能的方法确实很重要,就像你的那样,但我看不出中间表的形成位置或方式:您可以编辑您的答案以确保完整性吗?发送!
  • 中间表是OP给的表1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多