【问题标题】:Top-N By Decade for successive decades (in SQL Server)连续几十年按十年排名前 N(在 SQL Server 中)
【发布时间】:2020-08-23 07:57:49
【问题描述】:

我正在尝试获取最近 6 个十年中每一个按十年分组的 Top 5(即最常见)文档标题的排名列表。

文档标题不唯一。在任何给定的日历年中,可能有数十甚至数百个具有相同标题的文档。

以下查询是我所能做的。它给了我前 5 名的头衔,但仅限于“所有其他人”十年。

如何修改查询以获得其他十年的前 5 个标题?

SELECT
    Top 5 documentTitle AS 'Title',
    RANK() OVER (PARTITION BY calendarYear ORDER BY COUNT(documentTitle) DESC) AS Rank,
    COUNT(tblDocumentFact.inventionTitleEnID) AS 'Number of Occurrences',
    CASE
        WHEN calendarYear BETWEEN 2010 AND 2019 THEN '2010 - 2019'
        WHEN calendarYear BETWEEN 2000 AND 2009 THEN '2000 - 2009'
        WHEN calendarYear BETWEEN 1990 AND 1999 THEN '1990 - 1999'
        WHEN calendarYear BETWEEN 1980 AND 1989 THEN '1980 - 1989'
        WHEN calendarYear BETWEEN 1970 AND 1979 THEN '1970 - 1979'
        WHEN calendarYear BETWEEN 1960 AND 1969 THEN '1960 - 1969'
        ELSE 'all others'
    END AS Decade
FROM        tbldocumentTitleDimension
INNER JOIN  tblDocumentFact     ON  tbldocumentTitleDimension.documentTitleID   = tblDocumentFact.documentTitleID
INNER JOIN  tblDateDimension    ON  tblDocumentFact.publicationDateID           = tblDateDimension.dateID
GROUP BY    documentTitle,
            calendarYear
ORDER BY    [Number of Occurrences] DESC

【问题讨论】:

    标签: sql sql-server group-by greatest-n-per-group window-functions


    【解决方案1】:

    如果我正确地关注了你,你希望每十年进入前 5 名。如果是这样:

    • 你需要group by十年而不是日历年才能得到正确的计数;在子查询中计算十年更容易,因此您不必重复 case 表达式

    • 排名应按decade 分区而不是每年计算

    • 然后您可以使用该列在外部查询中进行过滤

    考虑:

    select *
    from (
        select
            dtd.documenttitle as title,
            rank() over (partition by dd.decade order by count(*) desc) as rnk,
            count(*) as number_of_occurrences,
            dd.decade
        from tbldocumentTitleDimension dtd
        inner join tblDocumentFact df on dtd.documenttitleid   = df.documenttitleid
        inner join  (
            select 
                dateid,
                case
                    when calendarYear between 2010 and 2019 then '2010 - 2019'
                    when calendarYear between 2000 and 2009 then '2000 - 2009'
                    when calendarYear between 1990 and 1999 then '1990 - 1999'
                    when calendarYear between 1980 and 1989 then '1980 - 1989'
                    when calendarYear between 1970 and 1979 then '1970 - 1979'
                    when calendarYear between 1960 and 1969 then '1960 - 1969'
                    else 'all others'
                end AS decade
                from tblDateDimension
        ) dd on df.publicationdateid  = dd.dateid
        group by dtd.documenttitle, dd.decade
    ) t
    where rnk <= 5
    order by decade, number_of_occurrences desc
    

    旁注:

    • 不要使用单引号作为标识符(尽管 SQL Server 允许这样做,单引号应保留用于 litteral stings,如 SQL 标准中所定义) - 更好的是,您可以使用不需要引用的标识符

    • 在多表查询中,始终使用它们所属的表来限定所有列名;我在这里做了一些假设

    • 除非您在 documentTitle 列中有您不想计算的 null 值,否则您可以使用 count(*) 而不是 count(documentTitle) - 这是直截了当且更有效的

    【讨论】:

    • 太棒了——非常感谢。我也很欣赏你的旁注。我将研究它们并尝试相应地改进我的 SQL。我还看到您使用rnk 作为列名,而不是Rank。 Rank 用作列名(至少在我的查询中),但我现在意识到这是一种不好的形式:SSMS 将这个词粉红色标记为保留,所以我应该抓住它。 count(*) 有效,因为 documentTitle 列中没有空值。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-23
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    相关资源
    最近更新 更多