SQL Server: как получить данные из низшей иерархии в таблице иерархии? - PullRequest
2 голосов
/ 16 апреля 2011

У меня есть иерархическая таблица, подобная этой

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.В этом примере 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 в качестве цели.

Пакет всегда самый высокийчлен в этом дереве и 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?) Без временных таблиц?Любой совет по этому поводу был бы очень признателен!

Ответы [ 3 ]

4 голосов
/ 16 апреля 2011

Я не уверен, что понимаю ваш вопрос, но вы могли бы искать это?

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'

Было бы очень полезно, если бы вы опубликовали ожидаемый результат из ваших выборочных данных и более подробное объяснение того, как этого следует достичь.

0 голосов
/ 16 апреля 2011

Это то, о чем вы говорите?

-- 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
0 голосов
/ 16 апреля 2011

Если вы хотите получить все 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

Возможно, я неправильно понял вашу проблему. А также, если есть определенное количество слоев, вы, вероятно, можете сделать это намного проще.

Я не тестировал код, и в нем может быть какая-то ошибка, но я надеюсь, что вы понимаете концепцию.

Также будьте осторожны. Если у вас есть иерархический цикл (потомок, имеющий дочерний элемент более высокого уровня), он будет застрять в вечном цикле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...