#sql #sql-server #sql-server-2005 #tsql #sql-server-2008
#sql #sql-сервер #sql-server-2005 #tsql #sql-server-2008
Вопрос:
У меня есть иерархическая таблица, подобная этой
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[EX_TABLE](
[PARENT_OBJ] [nvarchar](255) NOT NULL,
[PARENT_OBJ_TYPE] [nvarchar](64) NOT NULL,
[DESCEN_OBJ] [nvarchar](255) NOT NULL,
[DESCEN_OBJ_TYPE] [nvarchar](64) NOT NULL,
[DESCEN_OBJ_USAGE] [nvarchar](20) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'Batch_name_1', N'Batch', N'batch_name', N'Built In Function', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'Batch_name_1', N'Batch', N'print', N'Built In Function', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'Batch_name_1', N'Batch', N'batch_run_id', N'Built In Function', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'Batch_name_1', N'Batch', N'db_name', N'Built In Function', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'Batch_name_1', N'Batch', N'repo_name', N'Built In Function', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'Batch_name_1', N'Batch', N'WF_Batch_name_1', N'WF', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'Batch_name_1', N'Batch', N'table_attr', N'Built In Function', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'WF_Batch_name_1', N'WF', N'DF_Batch_name_1', N'DF', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'WF_Batch_name_1', N'WF', N'DF_Batch_name_1_2', N'DF', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1', N'DF', N'TABLE_1', N'Table', N'Source')
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1', N'DF', N'Query', N'Transform', N'Transform')
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1', N'DF', N'sysdate', N'Built In Function', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1', N'DF', N'TABLE_2', N'Table', N'Target')
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1', N'DF', N'TABLE_2', N'Table', N'Key')
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1', N'DF', N'DS_NAME', N'Ds', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1', N'DF', N'Key', N'Trans', N'Trans')
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1_2', N'DF', N'TABLE_1', N'Table', N'Source')
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1_2', N'DF', N'sysdate', N'Built In Function', NULL)
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1_2', N'DF', N'TABLE_3', N'Table', N'Target')
INSERT [dbo].[EX_TABLE] ([PARENT_OBJ], [PARENT_OBJ_TYPE], [DESCEN_OBJ], [DESCEN_OBJ_TYPE], [DESCEN_OBJ_USAGE]) VALUES (N'DF_Batch_name_1_2', N'DF', N'Key', N'Trans', N'Trans')
Идея состоит в том, чтобы пройти по дереву вверх от DF к WF и к пакету. В этом примере Batch_name_1
имеет много дочерних объектов (DESCEN_OBJ), но интересен только дочерний элемент WF ( WF_Batch_name_1
). WF_Batch_name_1
также имеет дочерние объекты (DESCEN_OBJ), которые являются объектами DF ( DF_Batch_name_1
, DF_Batch_name_1_2
).
DF_Batch_name_1
и DF_Batch_name_1_2
также имеют дочерние объекты, но меня интересуют только table
объекты (из DESCEN_OBJ_TYPE), которые имеют DESCEN_OBJ_USAGE в качестве цели.
Batch всегда является самым высоким элементом в этом дереве, а DF — самым низким, но между этими двумя могут быть и другие элементы. Убедитесь, что это только подмножество реальных данных.
Итак, как я могу запросить различное количество целевых таблиц (DESCEN_OBJ_USAGE) (DESCEN_OBJ_TYPE) для Batch_name_1 (PARENT_OBJ). В этом случае результат должен быть равен 2 (с реальными данными это не дает правильного результата, когда у меня много пакетов (самый высокий элемент в иерархии), поэтому необходим переход вверх к пакетам).:
SELECT COUNT(distinct descen_obj) as dobj FROM EX_TABLE
WHERE DESCEN_OBJ_TYPE = 'Table' and DESCEN_OBJ_USAGE = 'Target'
Иерархия представлена в поле DESCEN_OBJ. Можно ли этого достичь с помощью одного запроса (рекурсивный CTE?) без временных таблиц? Любые советы по этому поводу были бы весьма признательны!
Комментарии:
1. Можете ли вы опубликовать, как должен выглядеть вывод для этих данных?
Ответ №1:
Я не уверен, что понимаю ваш вопрос, но, возможно, вы ищете это?
with tree as (
select parent_obj,
parent_obj_type,
descen_obj,
descen_obj_usage,
descen_obj_type,
1 as level
from ex_table
where parent_obj = 'Batch_name_1'
union all
select e.parent_obj,
e.parent_obj_type,
e.descen_obj,
e.descen_obj_usage,
e.descen_obj_type,
t.level 1
from ex_table e
join tree t on e.parent_obj = t.descen_obj
)
select *
from tree
where descen_obj_type = 'Table'
and descen_obj_usage = 'Target'
Было бы очень полезно, если бы вы могли опубликовать ожидаемый результат из ваших выборочных данных и более подробное объяснение того, как этого следует достичь.
Комментарии:
1. Я отредактировал свой ответ, дайте мне знать, если это то, что вы ищете (он возвращает то, что вы ожидаете, с вашими образцами данных)
2. Большое вам спасибо! Изменив значение last select на это значение select COUNT (distinct descen_obj) как c, я получаю именно то, что хочу!!!
Ответ №2:
Если вы хотите получить все дочерние элементы DF для Batch_name_1, и их можно идентифицировать через [PARENT_OBJ_TYPE] = ‘DF’, и между ними неизвестное количество уровней / элементов, тогда я мог бы предложить использовать некоторые временные таблицы, подобные этой:
-- Creating a temporary table where we will store all found members from the lowest level
CREATE TABLE #DF (
[DESCEN_OBJ_TYPE] [nvarchar](64) NOT NULL,
[DESCEN_OBJ_USAGE] [nvarchar](20) NULL
)
CREATE TABLE #DESCEN (
[DESCEN_OBJ] [nvarchar](255) NOT NULL
)
-- First we get the initial top layer
SELECT *
INTO #PARENTS
FROM [dbo].[EX_TABLE]
WHERE [PARENT_OBJ] = 'Batch_name_1'
-- Loop running as long as there are children
WHILE EXISTS (SELECT * FROM #PARENTS)
BEGIN
-- Storing away the DF levelled members
INSERT INTO #DF ([DESCEN_OBJ_TYPE],[DESCEN_OBJ_USAGE])
SELECT [DESCEN_OBJ_TYPE],[DESCEN_OBJ_USAGE]
FROM #PARENTS WHERE [PARENT_OBJ_TYPE] = 'DF'
INSERT INTO #DESCEN ([DESCEN_OBJ])
SELECT DISTINCT [DESCEN_OBJ]
FROM #PARENT WHERE [PARENT_OBJ_TYPE] <> 'DF'
-- Clearing the parents table since we are going to fill it with the next layer
TRUNCATE TABLE #PARENTS
INSERT INTO #PARENTS
SELECT ex.*
FROM #DESCEN de
INNER JOIN [dbo].[EX_TABLE] ex ON ex.[PARENT_OBJ] = de.[DESCEN_OBJ]
TRUNCATE TABLE #DESCEN
END
-- Finally outputting
SELECT DISTINCT * FROM #DF
DROP TABLE #PARENTS
DROP TABLE #DESCEN
DROP TABLE #DF
Возможно, я неправильно понял вашу проблему. А также, если есть заданное количество уровней, вы, вероятно, можете сделать это гораздо более простым способом.
Я не тестировал код, и в нем может быть какая-то ошибка, но я надеюсь, что вы понимаете концепцию.
Кроме того, будьте осторожны. Если у вас есть цикл иерархии (потомок, имеющий элемент более высокого уровня в качестве дочернего элемента), это застрянет в вечном цикле.
Комментарии:
1. Спасибо, похоже, это не работает, я подумал, можно ли этого достичь с помощью рекурсивного CTE? Ну, я не знаю, как его создать…
Ответ №3:
Это то, о чем вы говорите?
-- flatten hierarchy while keeping top-level ID
WITH all_descendants(top_parent_obj, middle_obj, descen_obj) AS (
SELECT parent_obj, descen_obj, descen_obj
FROM dbo.EX_TABLE
WHERE PARENT_OBJ_TYPE = 'Batch'
UNION ALL
SELECT p.top_parent_obj, c.DESCEN_OBJ, c.DESCEN_OBJ
FROM all_descendants p
INNER JOIN dbo.EX_TABLE c
ON p.middle_obj = c.PARENT_OBJ
)
-- show distinct usages by top-level ID
SELECT d.top_parent_obj, o.DESCEN_OBJ_USAGE
FROM all_descendants d
INNER JOIN dbo.EX_TABLE o
ON d.descen_obj = o.DESCEN_OBJ
GROUP BY d.top_parent_obj, o.DESCEN_OBJ_USAGE
Результат таков:
Batch_name_1 NULL
Batch_name_1 Key
Batch_name_1 Source
Batch_name_1 Target
Batch_name_1 Trans
Batch_name_1 Transform