SQL Recursion и Pivot для создания иерархии - PullRequest
0 голосов
/ 20 сентября 2019

Мне нужно создать и применить иерархию к клиентам, где у меня нет контроля над таблицей клиентов или ее базой данных.

Для этого я создаю отдельную базу данных, которая будет содержать виртуальных клиентов икартографический стол.

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

Таблица VirtualCustomer - я могу контролироватьэтот дизайн таблицы.

Эти «клиенты» представляют иерархию, которая должна быть применена.

VirCustID    |    ParentVirCustID    |    Name
2001         |    NULL               |    Vehicle
2002         |    2001               |    Car
2003         |    NULL               |    Tech
2004         |    2003               |    Comms

HierarchyAssignment Table - У меня есть контроль над этим дизайном таблицы

Использование этой таблицы в качестве механизма присоединения клиента к виртуальному клиенту.Виртуальный клиент будет иметь оставшуюся часть иерархии.

Важно Я сопоставляю CustID с самым низким уровнем иерархии, поэтому необходимо выполнить возврат снизу вверх.

CustID - это идентификатор клиента за пределами этой базы данных, который я не могу контролировать.Мне также не нужно присоединяться к этому столу.

CustID    |    VirCustID
1001      |    2001
1002      |    2001
1003      |    2003

Я пытаюсь получить результат:

CustID    |    L1ID    |    L1Name    |    L2ID    |    L2Name 
1001      |    2001    |    Vehicle   |    2002    |    Car
1002      |    2001    |    Vehicle   |    2002    |    Car
1003      |    2003    |    Tech      |    2004    |    Comms
1004      |    NULL    |    NULL      |    NULL    |    NULL

На данный момент меня интересуют только 2 уровня, хотя возможно, мне нужно увеличить это, следовательно, используякартографический стол.Мне нужно иметь возможность поддерживать L n ID и имя.

Я думаю, что мне нужна рекурсия CTE и, возможно, поворот, и я попытался сделать несколько вещей, которые я собрал вместе из других вопросов и ответовхотя пока ничего не получилось.

Это один из сценариев, с которыми я играл.Я просто не знаю, с чего еще начать, и любые советы будут с благодарностью приняты.

WITH cp AS 
(
    SELECT  p.VirCustID, p.parentVirCustID, 0 as [level]
    FROM VirtualCustomer as p
    WHERE p.parentVirCustIDis null

    UNION ALL

    SELECT p2.VirCustID, p2.parentVirtualId, c.[level]+1
    FROM  VirtualCustomer as p2
    JOIN cp as c on p2.parentVirCustID= c.VirtCustID
)
select * from cp

Ответы [ 3 ]

0 голосов
/ 20 сентября 2019

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

SELECT DISTINCT c.custid, 
            Levelone.vircustid   AS l1id, 
            Levelone.NAME        AS l1name, 
            Leveltwo.vircustid   AS l2id, 
            Leveltwo.NAME        AS l2name, 
            Levelthree.vircustid AS l3id, 
            Levelthree.NAME      AS l3name, 
            Levelfour.vircustid  AS l4id, 
            Levelfour.NAME       AS l4name, 
            Levelfive.vircustid  AS l5id, 
            Levelfive.NAME       AS l5name, 
            Levelsix.vircustid   AS l6id, 
            Levelsix.NAME        AS l6name, 
            Levelseven.vircustid AS l7id, 
            Levelseven.NAME      AS l7name, 
            Leveleight.vircustid AS l8id, 
            Leveleight.NAME      AS l8name, 
            Levelnine.vircustid  AS l9id, 
            Levelnine.NAME       AS l9name, 
            Levelten.vircustid   AS l10id, 
            Levelten.NAME        AS l10name 
FROM   sourcecustomerids c 
   LEFT JOIN hierarchyassignment h 
          ON c.custid = h.custid 
   LEFT JOIN virtualcustomer Levelone 
          ON ( h.vircustid = Levelone.vircustid ) 
   LEFT JOIN virtualcustomer Leveltwo 
          ON ( Levelone.vircustid = Leveltwo.parentvircustid ) 
   LEFT JOIN virtualcustomer Levelthree 
          ON ( Leveltwo.vircustid = Levelthree.parentvircustid ) 
   LEFT JOIN virtualcustomer Levelfour 
          ON ( Levelthree.vircustid = Levelfour.parentvircustid ) 
   LEFT JOIN virtualcustomer Levelfive 
          ON ( Levelfour.vircustid = Levelfive.parentvircustid ) 
   LEFT JOIN virtualcustomer Levelsix 
          ON ( Levelfive.vircustid = Levelsix.parentvircustid ) 
   LEFT JOIN virtualcustomer Levelseven 
          ON ( Levelsix.vircustid = Levelseven.parentvircustid ) 
   LEFT JOIN virtualcustomer Leveleight 
          ON ( Levelseven.vircustid = Leveleight.parentvircustid ) 
   LEFT JOIN virtualcustomer Levelnine 
          ON ( Leveleight.vircustid = Levelnine.parentvircustid ) 
   LEFT JOIN virtualcustomer Levelten 
          ON ( Levelnine.vircustid = Levelten.parentvircustid ) 

Должно быть достаточно очевидно, как связать их вместе, если вам нужно добавить или удалить дополнительные слои.Добавление / удаление каждого слоя занимает около 5-10 секунд, если вы используете клавиатуру для жизни: D

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

HTH

0 голосов
/ 21 сентября 2019

Я отправляю этот альтернативный ответ, поскольку в оригинальном ответе по-прежнему есть смысл оставить онлайн-ответ (если вы решите пойти по пути, указанному Комби).Этот ответ использует как рекурсию (ваш первоначальный запрос, измененный), так и сводную.

Следующий код позволит вам построить иерархию по столбцам с несколькими оговорками.Если вы хотите увеличить количество слоев, вам все равно нужно изменить код.Причина этого в том, что SQL Server требует определения столбца (если мы не пишем динамический SQL).Кроме того, имена не распространяются в результате.Вы можете получить их с помощью функции или как часть оператора select.

Чтобы добавить новые уровни в вашу иерархию (10 из них включены), вы бы добавили дополнительный столбец (то есть [11] или [n] в массиве sq_consolidated и в массиве sq_merge добавьте max ([n]) в качестве LnID к sq_final.

Этот ответ также зависит от того, отображается ли вы на самом низком уровне иерархии (который был частью требований).

WITH
    sq_hierarchylevels AS
        (SELECT    vircustid
                  ,parentvircustid
                  ,name
                  ,1      AS hierlevel
                  ,[name] AS constname
           FROM    virtualcustomer
          WHERE    parentvircustid IS NULL
         UNION ALL
         SELECT    i.vircustid
                  ,i.parentvircustid
                  ,i.name
                  ,hierlevel + 1
                  ,hier.constname
           FROM    virtualcustomer  i
                   INNER JOIN sq_hierarchylevels hier ON hier.vircustid = i.parentvircustid),
    sq_consolidated AS
        (SELECT    *
           FROM    sq_hierarchylevels hier
                   PIVOT (max( vircustid )
                         FOR hierlevel
                         IN( [1],[2],[3],[4],[5],[6],[7],[8],[9],[10] )) AS piv
          WHERE    parentvircustid IS NOT NULL),
    sq_merge AS
        (SELECT    orig.vircustid
                  ,orig.parentvircustid
                  ,orig.[name]
                  ,vircustid   AS l1id
                  ,orig.[name] AS l1name
                  ,[2],[3],[4],[5],[6],[7],[8],[9],[10]
           FROM    virtualcustomer  orig
                   LEFT JOIN sq_consolidated fills ON (orig.name = fills.constname)
          WHERE    orig.parentvircustid IS NULL),
    sq_final AS
        (SELECT      vircustid
                    ,[name]
                    ,max( l1id ) AS l1id
                    ,max( [2] ) AS l2id
                    ,max( [3] ) AS l3id
                    ,max( [4] ) AS l4id
                    ,max( [5] ) AS l5id
                    ,max( [6] ) AS l6id
                    ,max( [7] ) AS l7id
                    ,max( [8] ) AS l8id
                    ,max( [9] ) AS l9id
                    ,max( [10] ) AS l10id
             FROM    sq_merge
         GROUP BY    vircustid, name)
SELECT      *
    FROM    sq_final
ORDER BY    vircustid
0 голосов
/ 20 сентября 2019

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

Вот db-скрипка сжелаемый результат: https://www.db -fiddle.com / f / hsdHCRJNcsg7ZpXbgJ7mbS / 0

Иерархическое связывание несколько противоречиво, так как вы связываете «назад» от родителя к потомку.

Вот запрос:

SELECT    cust.custid
         ,sq_levelone.vircustid AS l1id
         ,sq_levelone.name      AS l1name
         ,sq_leveltwo.vircustid AS l2id
         ,sq_leveltwo.name      AS l2name
  FROM    sq_sourcesystemcustids  cust
          LEFT JOIN sq_hierarchyassignment hier ON cust.custid = hier.custid
          LEFT JOIN sq_virtualcustomer sq_levelone ON (hier.vircustid = sq_levelone.vircustid)
          LEFT JOIN sq_virtualcustomer sq_leveltwo ON (sq_levelone.vircustid = sq_leveltwo.parentvircustid)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...