Разбить список имен на папки по начальной букве

#sql #tsql #ranking-functions

#sql #tsql #ранжирование-функции

Вопрос:

Учитывая набор данных типа:

 id    Name
   1  Aaa
   2  Aab
   3  AAc
…
 999  Zzz
  

Я хотел бы создать виртуальные папки, которые разделяют его по начальной букве. Например, я хотел бы передать 7 в функцию и получить 7 папок, например:

  • A-C
  • D-F
  • G-H
  • I-M
  • 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-P и P-T ).

Я на правильном пути? Есть ли более эффективный способ? Как мне предотвратить перекрытие?

Ответ №1:

Если вам просто нужно разделить начальный список букв на довольно равные группы, то вам, вероятно, следует сделать это примерно так, как вы делали это до сих пор, но в несколько ином порядке:

  1. Получить все начальные буквы, которые есть в таблице.

  2. Завершите результирующий список.

  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
  

Комментарии:

1. Ну, группы букв должны быть взвешены на основе исходных данных, а не на основе букв.

2. На мой взгляд, было бы справедливо, если бы вы отозвали принятие моего ответа и добавили свою последнюю часть спецификации к вашему вопросу. Я бы постарался найти правильное решение для вас, или, может быть, кому-то другому удалось бы сделать это раньше меня. В качестве альтернативы вы могли бы задать новый вопрос, конечно, если это вас устраивает.