Рейтинг:
4
Ahmed Elbaz
Основываясь на определении таблицы и предоставленных вами данных, я рекомендую создать функцию для возврата полного имени (полного имени) каждой учетной записи следующим образом:
CREATE FUNCTION [dbo].[GetAccountFullName](@AccountId INT) RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @AccountFullName NVARCHAR(MAX);
WITH HierarchyList_CTE
AS
(
SELECT Chart_ID, Chart_Name, ParentAccount
FROM Tbl_ChartOfAccountsTree
WHERE Chart_ID = @AccountId
UNION ALL
SELECT ST.Chart_ID, ST.Chart_Name, ST.ParentAccount
FROM Tbl_ChartOfAccountsTree ST
INNER JOIN HierarchyList_CTE CTE
ON ST.Chart_ID = CTE.ParentAccount
)
SELECT @AccountFullName = COALESCE(@AccountFullName+'/','') + ISNULL(Chart_Name, '/')
FROM HierarchyList_CTE
RETURN @AccountFullName
END
Приведенная выше функция принимает идентификатор учетной записи в данном случае Chart_ID и возвращает ее полное имя.
Вы можете использовать его для возврата полного имени для одной учетной записи следующим образом:
SELECT [dbo].[GetAccountFullName] (1102)
и вот результат
Lands/FixedAssets/Assets/MainTree
Или верните полное имя для всех записей следующим образом:
SELECT Chart_ID, Chart_Name, ParentAccount, [dbo].[GetAccountFullName] (Chart_ID) AS FullName
FROM Tbl_ChartOfAccountsTree
и вот результат
Chart_ID Chart_Name ParentAccount FullName
0 MainTree NULL MainTree
1000 Assets 0 Assets/MainTree
1100 FixedAssets 1000 FixedAssets/Assets/MainTree
1101 Buildings 1100 Buildings/FixedAssets/Assets/MainTree
1102 Lands 1100 Lands/FixedAssets/Assets/MainTree
Кроме того, рекомендуется добавить новый столбец в таблицу accounts (Tbl_ChartOfAccountsTree) для хранения значения полного имени вместо того, чтобы генерировать его каждый раз, когда оно вам нужно, поскольку предполагается, что оно редко изменяется.
Для этого используйте следующий код для добавления столбца:
ALTER TABLE dbo.Tbl_ChartOfAccountsTree ADD FullName nvarchar(MAX) NULL
А затем используйте приведенный ниже код для обновления всех учетных записей в таблице:
UPDATE [dbo].[Tbl_ChartOfAccountsTree]
SET [FullName] = [dbo].[GetAccountFullName] (Chart_ID)
Возможно, вам придется заново создавать полные имена всякий раз, когда в таблице происходят какие-либо изменения. Один из способов сделать это-добавить триггер в таблицу для запуска вышеупомянутого оператора update, когда происходит какое-либо изменение следующим образом:
CREATE TRIGGER TriggerUpdateFullNames
ON [dbo].[Tbl_ChartOfAccountsTree]
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE [dbo].[Tbl_ChartOfAccountsTree]
SET [FullName] = [dbo].[GetAccountFullName] (Chart_ID)
END
GO
Теперь каждый раз, когда происходит какое-либо изменение, полные имена будут автоматически обновляться.
Надеюсь, это поможет :)
Рейтинг:
2
Wendelius
Если я правильно понимаю вопрос, вы можете построить столбец "путь" в своем CTE
Рассмотрим следующий пример
Создайте тестовую таблицу и заполните ее некоторыми данными
create table locations (
id int,
parentid int,
place varchar(100)
)
insert into locations (id, parentid, place) values
(1, null, 'Europe'),
(2, 1, 'France'),
(3, 2, 'Paris'),
(4, 2, 'Marseille'),
(5, 2, 'Lyon'),
(6, 1, 'Italy'),
(7, 6, 'Rome'),
(8, 6, 'Milan'),
(9, 6, 'Venice'),
(10, 1, 'United Kingdom'),
(11, 10, 'London'),
(12, 10, 'Cambridge'),
(13, 10, 'Bath')
Запрос данных
with Places (id, parentid, place, level, path) AS (
select l.id,
l.parentid,
l.place,
1 as level,
cast('Continent' as varchar(1000))
from locations l
where l.parentid is null
union all
select l.id,
l.parentid,
l.place,
p.level + 1,
cast(case p.level
when 1 then p.path + '/Country'
when 2 then p.path + '/City'
end as varchar(1000))
from locations l
inner join places p on p.id = l.parentid
)
select *
from places
order by id
результат был бы таков
id parentid place level path
-- -------- ----- ----- --------
1 NULL Europe 1 Continent
2 1 France 2 Continent/Country
3 2 Paris 3 Continent/Country/City
4 2 Marseille 3 Continent/Country/City
5 2 Lyon 3 Continent/Country/City
6 1 Italy 2 Continent/Country
7 6 Rome 3 Continent/Country/City
8 6 Milan 3 Continent/Country/City
9 6 Venice 3 Continent/Country/City
10 1 United Kingdom 2 Continent/Country
11 10 London 3 Continent/Country/City
12 10 Cambridge 3 Continent/Country/City
13 10 Bath 3 Continent/Country/City
[ДОБАВЛЕН АЛЬТЕРНАТИВНЫЙ ПРИМЕР]
Что касается примера с футболистом. Идея та же, что и в предыдущем запросе. Во время каждого рекурсивного цикла объедините значения в виде пути к результирующему набору.
Рассмотреть следующее
Данные
create table person (
id int,
fatherid int,
name varchar(100)
)
insert into person (id, fatherid, name) values
(1, null, 'Aveiro'),
(2, 1, 'Dos Santos'),
(3, 2, 'Ronaldo'),
(4, 3, 'Cristiano')
Запрос
with PersonHier (id, fatherid, name, level, fullname) AS (
select p.id,
p.fatherid,
p.name,
1 as level,
cast(p.name as varchar(max))
from person p
where p.fatherid is null
union all
select p.id,
p.fatherid,
p.name,
h.level + 1,
concat(p.name, ' / ', h.FullName)
from person p
inner join PersonHier h on h.id = p.fatherid
)
select *
from PersonHier
order by id
результат
id fatherid name level fullname
-- -------- ----- ----- ------------
1 NULL Aveiro 1 Aveiro
2 1 Dos Santos 2 Dos Santos / Aveiro
3 2 Ronaldo 3 Ronaldo / Dos Santos / Aveiro
4 3 Cristiano 4 Cristiano / Ronaldo / Dos Santos / Aveiro
Abuamer
Спасибо, мой друг . но я сожалею, что это не решило проблему. так что, пожалуйста, помогите мне .
Wendelius
Не могли бы вы объяснить проблему более подробно, каков ожидаемый результат?
Abuamer
Хорошо, я приведу вам пример того, что я хочу, более подробно. Криштиану Роналду-Хороший Игрок, И Его Полное Имя (Кристаино Роналду Душ Сантуш Авейру).
Авейру-это великий дедушка с уровнем 0.
Дос Сантос - сын Авейру с уровнем 1.
Роналду-сын Дос Сантоса с уровнем 2.
И, наконец, Криштиану-сын Роналду с уровнем 3.
то что я хочу сделать это когда я выбираю Криштиану мой результат должен быть таким
(Криштиану / Роналду / Душ Сантуш / Авейру)
выход должен дать мне Криштиану / его отец /его дедушка/его прадедушка)
а это запрос на создание таблицы с иерархическим представлением
УСТАНОВИТЕ ANSI_NULLS НА
ГО
УСТАНОВИТЕ QUOTED_IDENTIFIER НА
ГО
Создайте таблицу [dbo].[Tbl_ChartOfAccountsTree](
[Chart_ID] [int] NOT NULL,
[Chart_Name] [nvarchar](500) NULL,
[Account_Level] [int] NULL,
[ParentAccount] [int] NULL,
[Accoutn_Type] [nvarchar](150) NULL,
[Направление] [nvarchar](150) NULL,
[OB] [decimal](18, 2) NULL,
[Дата] [дата] NULL,
Ограничение [PK_Tbl_ChartOfAccountsTree] первичный ключ КЛАСТЕРИЗОВАН
(
[Chart_ID] ASC
)С (КАК = ВЫКЛ, STATISTICS_NORECOMPUTE = OFF, ТО ЗНАЧЕНИЕ IGNORE_DUP_KEY = OFF, ТО ПАРАМЕТРЫ ALLOW_ROW_LOCKS = ON, ТО ALLOW_PAGE_LOCKS ИНСТРУКЦИИ =) НА [ОСНОВНОЙ]
) НА [ПЕРВИЧНОМ]
ГО
Вставить [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID], [Chart_Name], [Account_Level], [ParentAccount], [Accoutn_Type], [направление], [объединение], [дата]) значения (0, Н'Aveiro', 0, нуль, Н'Parent', нуль, литой(0.00 как decimal(18, 2)), ролях(Н-2019-07-01 как дата))
ГО
Вставить [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID], [Chart_Name], [Account_Level], [ParentAccount], [Accoutn_Type], [направление], [объединение], [дата]) значения (1000, Н'Dos Сантос', 1, 0, Н'Parent', Н'Balance', литой(0.00 как decimal(18, 2)), ролях(Н-2019-07-01 как дата))
ГО
Вставить [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID], [Chart_Name], [Account_Level], [ParentAccount], [Accoutn_Type], [направление], [объединение], [дата]) значения (1100, Н'Ronaldo', 2, 1000, Н'Parent', Н'Balance', литой(0.00 как decimal(18, 2)), ролях(Н-2019-07-01 как дата))
ГО
Вставить [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID], [Chart_Name], [Account_Level], [ParentAccount], [Accoutn_Type], [направление], [объединение], [дата]) значения (1101, Н'Cristiano', 3, 1100, Н'Child', Н'Balance', литой(0.00 как decimal(18, 2)), ролях(Н-2019-11-01 как дата))
ГО
ALTER TABLE [dbo].[Tbl_ChartOfAccountsTree] с проверкой добавить ограничение [FK_Tbl_ChartOfAccountsTree_Tbl_Chartofaccountstree] внешний ключ([ParentAccount])
Список литературы [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID])
ГО
ALTER TABLE [dbo].[Tbl_ChartOfAccountsTree] контрольное ограничение [FK_Tbl_ChartOfAccountsTree_Tbl_Chartofaccountstree]
ГО
так что пожалуйста есть ли какая нибудь возможная помощь
Abuamer
Хорошо, я приведу вам пример того, что я хочу, более подробно. Криштиану Роналду-Хороший Игрок, И Его Полное Имя (Кристаино Роналду Душ Сантуш Авейру).
Авейру-это великий дедушка с уровнем 0.
Дос Сантос - сын Авейру с уровнем 1.
Роналду-сын Дос Сантоса с уровнем 2.
И, наконец, Криштиану-сын Роналду с уровнем 3.
то что я хочу сделать это когда я выбираю Криштиану мой результат должен быть таким
(Криштиану / Роналду / Душ Сантуш / Авейру)
выход должен дать мне Криштиану / его отец /его дедушка/его прадедушка)
а это запрос на создание таблицы с иерархическим представлением
УСТАНОВИТЕ ANSI_NULLS НА
ГО
УСТАНОВИТЕ QUOTED_IDENTIFIER НА
ГО
Создайте таблицу [dbo].[Tbl_ChartOfAccountsTree](
[Chart_ID] [int] NOT NULL,
[Chart_Name] [nvarchar](500) NULL,
[Account_Level] [int] NULL,
[ParentAccount] [int] NULL,
[Accoutn_Type] [nvarchar](150) NULL,
[Направление] [nvarchar](150) NULL,
[OB] [decimal](18, 2) NULL,
[Дата] [дата] NULL,
Ограничение [PK_Tbl_ChartOfAccountsTree] первичный ключ КЛАСТЕРИЗОВАН
(
[Chart_ID] ASC
)С (КАК = ВЫКЛ, STATISTICS_NORECOMPUTE = OFF, ТО ЗНАЧЕНИЕ IGNORE_DUP_KEY = OFF, ТО ПАРАМЕТРЫ ALLOW_ROW_LOCKS = ON, ТО ALLOW_PAGE_LOCKS ИНСТРУКЦИИ =) НА [ОСНОВНОЙ]
) НА [ПЕРВИЧНОМ]
ГО
Вставить [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID], [Chart_Name], [Account_Level], [ParentAccount], [Accoutn_Type], [направление], [объединение], [дата]) значения (0, Н'Aveiro', 0, нуль, Н'Parent', нуль, литой(0.00 как decimal(18, 2)), ролях(Н-2019-07-01 как дата))
ГО
Вставить [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID], [Chart_Name], [Account_Level], [ParentAccount], [Accoutn_Type], [направление], [объединение], [дата]) значения (1000, Н'Dos Сантос', 1, 0, Н'Parent', Н'Balance', литой(0.00 как decimal(18, 2)), ролях(Н-2019-07-01 как дата))
ГО
Вставить [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID], [Chart_Name], [Account_Level], [ParentAccount], [Accoutn_Type], [направление], [объединение], [дата]) значения (1100, Н'Ronaldo', 2, 1000, Н'Parent', Н'Balance', литой(0.00 как decimal(18, 2)), ролях(Н-2019-07-01 как дата))
ГО
Вставить [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID], [Chart_Name], [Account_Level], [ParentAccount], [Accoutn_Type], [направление], [объединение], [дата]) значения (1101, Н'Cristiano', 3, 1100, Н'Child', Н'Balance', литой(0.00 как decimal(18, 2)), ролях(Н-2019-11-01 как дата))
ГО
ALTER TABLE [dbo].[Tbl_ChartOfAccountsTree] с проверкой добавить ограничение [FK_Tbl_ChartOfAccountsTree_Tbl_Chartofaccountstree] внешний ключ([ParentAccount])
Список литературы [dbo].[Tbl_ChartOfAccountsTree] ([Chart_ID])
ГО
ALTER TABLE [dbo].[Tbl_ChartOfAccountsTree] контрольное ограничение [FK_Tbl_ChartOfAccountsTree_Tbl_Chartofaccountstree]
ГО
так что пожалуйста есть ли какая нибудь возможная помощь
Wendelius
Я попытался привести еще один пример, основанный на именах, касающихся Криштиану Роналду. Смотрите обновленный ответ, надеюсь, что это поможет.