Рекурсивный CTE по многим ко многим таблицам - PullRequest
0 голосов
/ 22 октября 2018

Я работаю в рекурсивном CTE, чтобы отслеживать все отношения в БД, используя внешние ключи, для создания некоторых тестовых данных.Все работает хорошо, вплоть до того момента, когда я попал в таблицу, которая содержит отношения «многие ко многим».Я взглянул на некоторые другие ответы, связанные с таблицами «многие ко многим», но они просто не сошлись со мной - может кто-нибудь взглянуть на то, что у меня есть, и помочь мне указать верное направление?В частности, происходит то, что я достигаю таблицы, которая является таблицей Бюджет / Клиент (id, budgettid, clientid) со стороны Клиента.В этот момент рекурсия останавливается;Я хотел бы / ожидаю, что он перейдет к таблице бюджета (через budgettid) и продолжит к любым связанным таблицам после этого.

|Users      |      |Client       |       |BudgetClient |      |Budget       |
|userid (pk)|==\   |clientid (pk)|==\    |id (pk)      |   /==|budgetid (pk)|
                \==|userid (fk)  |   \   |budgetid (fk)|==/
                                      \==|clientid (fk)|

Существующий код (текущая попытка) ниже:

    WITH cte AS
    (
        SELECT DISTINCT fk.object_id, fk.schema_id, fk.parent_object_id, fc.parent_column_id, t.schema_id AS referenced_schema_id, fk.referenced_object_id, ic.column_id AS referenced_column_id, 1 AS [Level]
        FROM sys.foreign_keys fk
            INNER JOIN sys.tables t ON fk.referenced_object_id = t.object_id
            INNER JOIN sys.foreign_key_columns fc ON fk.object_id = fc.constraint_object_id
            INNER JOIN sys.indexes i ON fk.referenced_object_id = i.object_id AND i.is_primary_key = 1
            INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
        WHERE fk.type = 'F' 
            AND fk.referenced_object_id = OBJECT_ID(N'dbo.Users', N'U')

        UNION ALL

        SELECT fk.object_id, fk.schema_id, fk.parent_object_id, fc.parent_column_id, t.schema_id, fk.referenced_object_id, ic.column_id AS referenced_column_id, cte.[Level] + 1
        FROM sys.foreign_keys fk     
            INNER JOIN sys.tables t ON fk.referenced_object_id = t.object_id
            INNER JOIN sys.foreign_key_columns fc ON fk.object_id = fc.constraint_object_id
            INNER JOIN sys.indexes i ON fk.referenced_object_id = i.object_id AND i.is_primary_key = 1
            INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
            INNER JOIN cte ON fk.referenced_object_id = cte.parent_object_id
        WHERE fk.type = 'F' 
            AND fk.referenced_object_id <> cte.referenced_object_id
    ),
    cteHierarchy AS (
        SELECT DISTINCT
            OBJECT_NAME(cte.object_id) AS ReferringKey,
            SCHEMA_NAME(cte.schema_id) AS ReferringSchema,
            OBJECT_NAME(cte.parent_object_id) as ReferringTable,
            cte.parent_object_id AS reftableid,
            COL_NAME(cte.parent_object_id,cte.parent_column_id) ReferringColumn,
            SCHEMA_NAME(cte.referenced_schema_id) AS ReferencedSchema,
            OBJECT_NAME(cte.referenced_object_id) as ReferencedTable,
            COL_NAME(cte.referenced_object_id,cte.referenced_column_id) ReferencedColumn,
            [Level]
        FROM cte
    )
    SELECT ReferringKey, ReferringSchema, ReferringTable, ReferringColumn, ReferencedSchema, ReferencedTable, ReferencedColumn, [Level]
    FROM cteHierarchy
    ORDER BY [Level], ReferencedSchema, ReferencedTable, ReferringTable;

Пример данных ниже.DML не является обязательным для этого вопроса, но при условии, чтобы быть полным.

CREATE TABLE Users
(
    userid INT NOT NULL,
    CONSTRAINT PK_Users PRIMARY KEY CLUSTERED (userid)
);

CREATE TABLE Client
(
    clientid INT NOT NULL,
    userid INT NOT NULL,
    CONSTRAINT PK_Client PRIMARY KEY CLUSTERED (clientid),
    CONSTRAINT FK_Client_Users FOREIGN KEY (userid) REFERENCES Users (userid)
);

CREATE TABLE Budget
(
    budgetid INT NOT NULL,
    CONSTRAINT PK_Budget PRIMARY KEY CLUSTERED (budgetid)
);

CREATE TABLE BudgetClient
(
    id INT NOT NULL IDENTITY(1,1),
    budgetid INT NOT NULL,
    clientid INT NOT NULL,
    CONSTRAINT PK_BudgetClient PRIMARY KEY CLUSTERED (id),
    CONSTRAINT FK_BudgetClient_Budget FOREIGN KEY (budgetid) REFERENCES Budget (budgetid),
    CONSTRAINT FK_BudgetClient_Client FOREIGN KEY (clientid) REFERENCES Client (clientid)
);

CREATE TABLE Company
(
    companyid INT NOT NULL,
    userid INT NOT NULL,
    CONSTRAINT PK_Company PRIMARY KEY CLUSTERED (companyid),
    CONSTRAINT FK_Company_Users FOREIGN KEY (userid) REFERENCES Users (userid)
);

CREATE TABLE CompanyType
(
    companytypeid INT NOT NULL,
    companyid INT NOT NULL,
    CONSTRAINT PK_CompanyType PRIMARY KEY CLUSTERED (companytypeid),
    CONSTRAINT FK_CompanyType_Company FOREIGN KEY (companyid) REFERENCES Company (companyid)
);

CREATE TABLE CompanyTypeCategory
(
    companytypecategoryid INT NOT NULL,
    companytypeid INT NOT NULL,
    CONSTRAINT PK_CompanyTypeCategory PRIMARY KEY CLUSTERED (companytypecategoryid),
    CONSTRAINT FK_CompanyTypeCategory_CompanyType FOREIGN KEY (companytypeid) REFERENCES CompanyType (companytypeid),
);

INSERT INTO Users (userid)
    VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);

INSERT INTO Client (clientid,userid)
    VALUES (6,10),(7,3),(8,8),(9,5),(10,6);

INSERT INTO Budget (budgetid)
    VALUES (15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25);

INSERT INTO BudgetClient (budgetid,clientid)
    VALUES (15,6),(16,7),(17,8),(19,9),(18,10),(21,6),(20,7),(25,8),(23,9),(24,10);

INSERT INTO Company (companyid,userid)
    VALUES (1,7),(5,1),(8,9),(12,2),(15,4);

INSERT INTO CompanyType (companytypeid, companyid)
    VALUES (1,1),(2,5),(3,8),(4,12),(5,15),(6,5),(7,8);

INSERT INTO CompanyTypeCategory (companytypecategoryid,companytypeid)
    VALUES (1,7),(2,1),(3,3),(4,2),(5,1),(6,1),(7,5),(8,4),(9,6),(10,7);

Белые / зеленые линии, за исключением столбца «Тип», в настоящее время возвращаются.Зеленая линия - это таблица «многие ко многим», а красная линия - это то, что я хочу вернуть (другая «один ко многим», связанная с зеленой таблицей «BudgetClient»).По сути, рекурсия использует внешние ключи для отслеживания связей таблицы.Итак, здесь верхняя / якорная таблица - «Пользователи», у которой есть две дочерние таблицы - «Клиент» и «Компания», и отношения один ко многим.В свою очередь, у клиента есть одна связанная таблица, BudgetClient, во многих отношениях с Budget - BudgetClient связывает Client & Budget вместе.

Для ясности, мой желаемый результат состоит в том, что ВСЕ строки на изображении нижебудет возвращен.

enter image description here

...