【问题标题】:Partition a list of names into folders by initial letter按首字母将名称列表分区到文件夹中
【发布时间】:2011-05-07 18:35:17
【问题描述】:

给定一组数据,例如:

id    Name
   1  Aaa
   2  Aab
   3  AAc
…
 999  Zzz

,我想创建按首字母分区的虚拟文件夹。例如,我想将7 传递给一个函数并获取7个文件夹,例如:

  • A-C
  • D-F
  • G-H
  • 我-我
  • N-Q
  • R-S
  • T-Z

...每个都包含各自的值(例如,T-Z 将包含 Zzz)。我发现我可以使用NTILE() 来相当接近预期的结果:

WITH Ntiles(Name, Ntile) AS (
    SELECT Name, NTILE(7) OVER(ORDER BY Name) FROM #Projects
)
SELECT MIN(LEFT(N.Name, 1)) + '-' + MAX(LEFT(N.Name, 1))
FROM Ntiles N 
GROUP BY Ntile

为了添加所需的值,我正在做另外两个连接:

WITH Ntiles(Name, Ntile) AS (
    SELECT Name, NTILE(7) OVER(ORDER BY Name) FROM #Projects
) SELECT P.Name, (
    SELECT MIN(LEFT(N1.Name, 1)) + '-' + MAX(LEFT(N1.Name, 1)) FROM Ntiles N1 
    WHERE N1.Ntile = N2.Ntile
GROUP BY N1.Ntile
) FROM #Projects P INNER JOIN Ntiles N2 ON P.Name = N2.Name

……这似乎有点低效。

但这也是错误的:有重叠(例如,字母P 出现在J-PP-T 中)。

我在正确的轨道上吗?有没有更有效的方法?如何防止重叠?

【问题讨论】:

    标签: sql tsql ranking-functions


    【解决方案1】:

    如果您只是需要将初始字母列表分成相当相等的组,那么您可能应该大致按照您迄今为止的做法,但顺序略有不同:

    1. 获取表格中的所有首字母。

    2. NTILE 结果列表。

    3. 对 NTILEd 结果集进行分组。

    WITH letters AS (
      SELECT
        Letter = LEFT(Name, 1)
      FROM #Projects
      GROUP BY LEFT(Name, 1)
    ),
    ntiled AS (
      SELECT
        Letter,
        Folder = NTILE(7) OVER (ORDER BY Letter)
      FROM letters
    )
    SELECT
      Folder,
      FolderCaption = MIN(Letter) + '-' + MAX(Letter)
    FROM ntiled
    GROUP BY Folder
    

    【讨论】:

    • 嗯,字母组应该根据原始数据进行加权,而不是根据字母。
    • 在我看来,如果您撤销对我的回答的接受将您的最后一条规范添加到您的问题中,这将是公平的。我会尝试为您找到正确的解决方案,或者也许其他人会比我更快地做到这一点。当然,您也可以提出一个新问题,如果这适合您的话。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    相关资源
    最近更新 更多