Иногда возникает необходимость сортировки иерархического списка в строковых полях ранее уже созданной таблицы. Это очень просто сделать с помощью конвейера CTE в SQL.
DECLARE @t TABLE (txt varchar(50)) INSERT INTO @t (txt) VALUES ('1_____') INSERT INTO @t (txt) VALUES ('1.2. _____') INSERT INTO @t (txt) VALUES ('1.2.1._____') INSERT INTO @t (txt) VALUES ('1.2.10._____') INSERT INTO @t (txt) VALUES ('1.2.7._____') INSERT INTO @t (txt) VALUES ('2. _____') INSERT INTO @t (txt) VALUES ('2.2 _____') INSERT INTO @t (txt) VALUES ('2.2.10._____') INSERT INTO @t (txt) VALUES ('2.2.3.1._____') INSERT INTO @t (txt) VALUES ('22_____') ;WITH points (id, p1, p2, p3, p4, p5, p6, p7, p8, p9, it) AS ( SELECT id = RTRIM(LEFT(t.txt, PATINDEX('%[^.0-9]%', t.txt) - 1)), p1 = CONVERT(int, NULL), p2 = CONVERT(int, NULL), p3 = CONVERT(int, NULL), p4 = CONVERT(int, NULL), p5 = CONVERT(int, NULL), p6 = CONVERT(int, NULL), p7 = CONVERT(int, NULL), p8 = CONVERT(int, NULL), p9 = CONVERT(int, NULL), it = 0 FROM @t t UNION ALL SELECT id = p.id, p1 = NULLIF(CHARINDEX('.', p.id, 1), 0), p2 = NULLIF(CHARINDEX('.', p.id, 1 + p.p1), 0), p3 = NULLIF(CHARINDEX('.', p.id, 1 + p.p2), 0), p4 = NULLIF(CHARINDEX('.', p.id, 1 + p.p3), 0), p5 = NULLIF(CHARINDEX('.', p.id, 1 + p.p4), 0), p6 = NULLIF(CHARINDEX('.', p.id, 1 + p.p5), 0), p7 = NULLIF(CHARINDEX('.', p.id, 1 + p.p6), 0), p8 = NULLIF(CHARINDEX('.', p.id, 1 + p.p7), 0), p9 = NULLIF(CHARINDEX('.', p.id, 1 + p.p8), 0), it = p.it + 1 FROM points p WHERE p.it < 10 ), levels (id, v1, v2, v3, v4, v5, v6, v7, v8, v9) AS ( SELECT id = p.id, v1 = CONVERT(int, SUBSTRING(id, 1, ISNULL(p.p1 - 1, LEN(p.id) ))), v2 = CONVERT(int, SUBSTRING(id, p.p1 + 1, ISNULL(p.p2 - p.p1 - 1, LEN(p.id) - p.p1))), v3 = CONVERT(int, SUBSTRING(id, p.p2 + 1, ISNULL(p.p3 - p.p2 - 1, LEN(p.id) - p.p2))), v4 = CONVERT(int, SUBSTRING(id, p.p3 + 1, ISNULL(p.p4 - p.p3 - 1, LEN(p.id) - p.p3))), v5 = CONVERT(int, SUBSTRING(id, p.p4 + 1, ISNULL(p.p5 - p.p4 - 1, LEN(p.id) - p.p4))), v6 = CONVERT(int, SUBSTRING(id, p.p5 + 1, ISNULL(p.p6 - p.p5 - 1, LEN(p.id) - p.p5))), v7 = CONVERT(int, SUBSTRING(id, p.p6 + 1, ISNULL(p.p7 - p.p6 - 1, LEN(p.id) - p.p6))), v8 = CONVERT(int, SUBSTRING(id, p.p7 + 1, ISNULL(p.p8 - p.p7 - 1, LEN(p.id) - p.p7))), v9 = CONVERT(int, SUBSTRING(id, p.p8 + 1, ISNULL(p.p9 - p.p8 - 1, LEN(p.id) - p.p8))) FROM points p WHERE p.it = 10 ) SELECT num = CASE RIGHT(v.id, 1) WHEN '.' THEN v.id ELSE v.id + '.' END, txt = LTRIM(RIGHT(t.txt, LEN(t.txt) - LEN(v.id))) FROM @t t INNER JOIN levels v ON v.id = RTRIM(LEFT(t.txt, PATINDEX('%[^.0-9]%', t.txt) - 1)) ORDER BY ISNULL(v.v1, 0), ISNULL(v.v2, 0), ISNULL(v.v3, 0), ISNULL(v.v4, 0), ISNULL(v.v5, 0), ISNULL(v.v6, 0), ISNULL(v.v7, 0), ISNULL(v.v8, 0), ISNULL(v.v9, 0)
Комментарии
Отправить комментарий