我正在使用递归 CTE 来跟踪数据库中的所有关系,使用外键来创建一些测试数据。一切都运行良好,直到我找到一个包含多对多关系的表。我已经查看了与多对多表相关的其他一些答案,但它只是没有点击我 - 有人可以看看我所拥有的并帮助我指出正确的方向吗?具体来说,我正在从客户端到达一个预算/客户表(id、budgetid、clientid)的表。此时递归停止;我希望/期望它遍历预算表(通过budgetid)并在此之后继续访问任何相关表。
|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”表相关的另一个“一对多”)。本质上,递归是使用外键来跟踪表关系。所以在这里,顶部/锚点表是用户,它有两个子表——客户和公司,都是一对多的关系。反过来,Client 有一个相关表 BudgetClient,它与 BudgetClient 具有多对多关系 - BudgetClient 将 Client 和 Budget 联系在一起。
需要明确的是,我想要的结果是将返回下图中的所有行。