SQL - многоуровневый список номеров с отступом - PullRequest
0 голосов
/ 07 августа 2020

Я пытаюсь создать запрос на основе иерархической таблицы родительских / дочерних элементов. IE, у меня есть parentID, а у него childID. Однако этот ChildID также может быть родительским и вниз по дереву go. Однако цель - получить столбец, представляющий структуру в виде чисел. Например:

1

1.1

1.1.1

1.1.2

1.1.3

1.2

У меня здесь образец структуры таблицы SQL Fiddle

CREATE TABLE [dbo].[_test](
    [ParentItemSpecID] [int] NULL,
    [ChildItemSpecID] [int] NULL,
    [TotalQtyPerRoot] [float] NULL,
    [level] [float] NULL,
    [TreeSort] [int] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (1, 2, 1, 1, 0)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (2, 3, 1, 2, 1)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 4, 1, 3, 2)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (4, 5, 1, 4, 3)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (5, 6, 1, 5, 4)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (6, 7, 1, 6, 5)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (6, 8, 1, 6, 6)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (6, 9, 2, 6, 7)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (6, 10, 1, 6, 8)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (6, 11, 1, 6, 9)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (6, 12, 1, 6, 10)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (5, 13, 1, 5, 11)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (4, 14, 1, 4, 12)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 15, 1, 3, 13)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 16, 2, 3, 14)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 17, 1, 3, 15)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 18, 7, 3, 16)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 19, 2, 3, 17)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 20, 2, 3, 18)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 21, 2, 3, 19)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 22, 1, 3, 20)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 23, 1, 3, 21)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 24, 24, 3, 22)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 25, 24, 3, 23)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 26, 24, 3, 24)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 27, 2, 3, 25)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 28, 4, 4, 26)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 29, 2, 4, 27)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 30, 4, 4, 28)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 31, 2, 4, 29)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 32, 2, 4, 30)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 33, 2, 4, 31)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 34, 2, 4, 32)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 35, 2, 4, 33)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 36, 4, 4, 34)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 37, 2, 4, 35)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (27, 38, 0.04, 4, 36)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 39, 4, 3, 37)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 40, 1, 3, 38)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 41, 1, 3, 39)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 42, 1, 3, 40)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 43, 2, 3, 41)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (3, 44, 1, 3, 42)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (44, 45, 1, 4, 43)
GO
INSERT [dbo].[_test] ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES (45, 46, 1, 5, 44)
GO

Если вы ссылаетесь на Parent ID 3, ChildID 27. На этом этапе нумерация должна выглядят как 1.1.14, а затем начинаются с go до 1.1.14.1, 1.1.14.2, 1.1.14.3

Я пробовал несколько рангов, row_number (), Dense_rank ... Я просто не могу понять это то, что каждый раз, когда он переходит на новый уровень (уровень +1), он должен принимать значение предыдущей строки и снова начинать отсчет. Любая помощь будет оценена. Я стараюсь избегать использования al oop или курсора. Спасибо.

1 Ответ

0 голосов
/ 08 августа 2020

Это решение использует рекурсивное общее табличное выражение (rcte), чтобы получить нужную нумерацию (Number). Я также включил иерархический путь (PathWithIds) в качестве бонуса.

Ваши данные немного необычны, так как нет строки с ChildItemSpecID=1, ParentItemSpecID=null as root элементом. Обычно root в рекурсивном CTE определяется как «элемент без родителя» (ParentItemSpecID=null). Это решение имеет более жестко запрограммированный подход с некоторыми перечисленными альтернативами.

Я пропустил столбцы TotalQtyPerRoot, level и TreeSort в результате. Мне не ясно, являются ли эти столбцы частью ваших данных или результатом ваших попыток. Вы можете добавить их или даже вычислить их как часть рекурсивного CTE, если хотите.

Пример данных

declare @_test table
(
    [ParentItemSpecID] [int] NULL,
    [ChildItemSpecID] [int] NULL,
    [TotalQtyPerRoot] [float] NULL,
    [level] [float] NULL,
    [TreeSort] [int] NULL
);

INSERT @_test ([ParentItemSpecID], [ChildItemSpecID], [TotalQtyPerRoot], [level], [TreeSort]) VALUES
(1, 2, 1, 1, 0),
(2, 3, 1, 2, 1),
(3, 4, 1, 3, 2),
(4, 5, 1, 4, 3),
(5, 6, 1, 5, 4),
(6, 7, 1, 6, 5),
(6, 8, 1, 6, 6),
(6, 9, 2, 6, 7),
(6, 10, 1, 6, 8),
(6, 11, 1, 6, 9),
(6, 12, 1, 6, 10),
(5, 13, 1, 5, 11),
(4, 14, 1, 4, 12),
(3, 15, 1, 3, 13),
(3, 16, 2, 3, 14),
(3, 17, 1, 3, 15),
(3, 18, 7, 3, 16),
(3, 19, 2, 3, 17),
(3, 20, 2, 3, 18),
(3, 21, 2, 3, 19),
(3, 22, 1, 3, 20),
(3, 23, 1, 3, 21),
(3, 24, 24, 3, 22),
(3, 25, 24, 3, 23),
(3, 26, 24, 3, 24),
(3, 27, 2, 3, 25),
(27, 28, 4, 4, 26),
(27, 29, 2, 4, 27),
(27, 30, 4, 4, 28),
(27, 31, 2, 4, 29),
(27, 32, 2, 4, 30),
(27, 33, 2, 4, 31),
(27, 34, 2, 4, 32),
(27, 35, 2, 4, 33),
(27, 36, 4, 4, 34),
(27, 37, 2, 4, 35),
(27, 38, 0.04, 4, 36),
(3, 39, 4, 3, 37),
(3, 40, 1, 3, 38),
(3, 41, 1, 3, 39),
(3, 42, 1, 3, 40),
(3, 43, 2, 3, 41),
(3, 44, 1, 3, 42),
(44, 45, 1, 4, 43),
(45, 46, 1, 5, 44);

Решение

with rcte as
(
    select  t1.ChildItemSpecID,
            t1.ParentItemSpecID,
            convert(nvarchar, convert(nvarchar, t1.ParentItemSpecID) + '/' + convert(nvarchar, t1.ChildItemSpecID)) as 'PathWithIds',
            convert(nvarchar, 1) as 'Number'
    from @_test t1
    where t1.ParentItemSpecID = 1   -- select root element (option 1)
       -- t1.ChildItemSpecID = 2    -- select root element (option 2)
       -- t1.level = 1              -- select root element (option 3)
       union all
    select  t2.ChildItemSpecID,
            t2.ParentItemSpecID,
            convert(nvarchar, t1.PathWithIds + '/' + convert(nvarchar, t2.ChildItemSpecID)), -- extend number starting from parent number
            convert(nvarchar, t1.Number + '.' + convert(nvarchar, row_number() over(order by t2.ChildItemSpecID)))
    from @_test t2
    join rcte t1
        on t1.ChildItemSpecID = t2.ParentItemSpecID
)
select rcte.ChildItemSpecID, rcte.ParentItemSpecID, rcte.PathWithIds, rcte.Number
from rcte
order by rcte.Number;

Результат

ChildItemSpecID ParentItemSpecID PathWithIds      Number
--------------- ---------------- ---------------- -------------
2               1                1/2              1
3               2                1/2/3            1.1
4               3                1/2/3/4          1.1.1
5               4                1/2/3/4/5        1.1.1.1
6               5                1/2/3/4/5/6      1.1.1.1.1
7               6                1/2/3/4/5/6/7    1.1.1.1.1.1
8               6                1/2/3/4/5/6/8    1.1.1.1.1.2
9               6                1/2/3/4/5/6/9    1.1.1.1.1.3
10              6                1/2/3/4/5/6/10   1.1.1.1.1.4
11              6                1/2/3/4/5/6/11   1.1.1.1.1.5
12              6                1/2/3/4/5/6/12   1.1.1.1.1.6
13              5                1/2/3/4/5/13     1.1.1.1.2
14              4                1/2/3/4/14       1.1.1.2
23              3                1/2/3/23         1.1.10
24              3                1/2/3/24         1.1.11
25              3                1/2/3/25         1.1.12
26              3                1/2/3/26         1.1.13
27              3                1/2/3/27         1.1.14
28              27               1/2/3/27/28      1.1.14.1
37              27               1/2/3/27/37      1.1.14.10
38              27               1/2/3/27/38      1.1.14.11
29              27               1/2/3/27/29      1.1.14.2
30              27               1/2/3/27/30      1.1.14.3
31              27               1/2/3/27/31      1.1.14.4
32              27               1/2/3/27/32      1.1.14.5
33              27               1/2/3/27/33      1.1.14.6
34              27               1/2/3/27/34      1.1.14.7
35              27               1/2/3/27/35      1.1.14.8
36              27               1/2/3/27/36      1.1.14.9
39              3                1/2/3/39         1.1.15
40              3                1/2/3/40         1.1.16
41              3                1/2/3/41         1.1.17
42              3                1/2/3/42         1.1.18
43              3                1/2/3/43         1.1.19
15              3                1/2/3/15         1.1.2
44              3                1/2/3/44         1.1.20
45              44               1/2/3/44/45      1.1.20.1
46              45               1/2/3/44/45/46   1.1.20.1.1
16              3                1/2/3/16         1.1.3
17              3                1/2/3/17         1.1.4
18              3                1/2/3/18         1.1.5
19              3                1/2/3/19         1.1.6
20              3                1/2/3/20         1.1.7
21              3                1/2/3/21         1.1.8
22              3                1/2/3/22         1.1.9
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...