Given a set of data like:
id Name
1 Aaa
2 Aab
3 AAc
…
999 Zzz
, I'd like to create virtual folders that partition it by initial letter. For example, I'd like to pass 7
to a function and get 7 folders, e.g.:
- A-C
- D-F
- G-H
- I-M
- N-Q
- R-S
- T-Z
…which each contain the respective value (e.g. T-Z
will contain Zzz
). I've figured out that I can use NTILE()
to get fairly close to the desired result:
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
To add the desired values, I'm doing another two joins:
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
…which seems a bit inefficient.
But it's also wrong: there's overlap (for instance, the letter P
appears both in J-P
and P-T
).
Am I on the right track? Is there a more efficient way? How do I prevent overlap?