sql - 在多对多实体之间查找sql​​连接组件

标签 sql sql-server algorithm graph

我有两个基本实体:财务计划和采购请求。这两个实体是多对多关系:

CREATE TABLE FinancialPlan
(
    ID int NOT NULL,
    PRIMARY KEY (ID)
);

CREATE TABLE PurchaseRequest
(
    ID int NOT NULL,
    PRIMARY KEY (ID)
);

CREATE TABLE FP_PR
(
    FP_ID FOREIGN KEY REFERENCES FinancialPlan(ID),
    PR_ID FOREIGN KEY REFERENCES PurchaseRequest(ID)
);

问题:查找与指定计划相关的所有请求,以及与请求相关、与指定计划相关的所有计划,...

模型可以表示为一个图,其中每个节点代表一个计划,或一个请求,每条边代表一种关系,那么问题可以改写为找到指定节点所属的连通组件.

例子:

Plan     Request    FP_PR

ID  |    ID  |      FP_ID|PR_ID|
----|    ----|      -----|-----|
1   |    1   |      1    |1    |
2   |    2   |      2    |1    |
3   |    3   |      2    |2    |
4   |               3    |2    |
5   |               4    |2    |
                    5    |3    |

查找 finplan ID=1 的连通分量

期望的输出:

FP_ID | PR_ID|
------+------+
1     | 1    |
2     | 1    |
2     | 2    |
3     | 2    |
4     | 2    |

我目前在应用程序端递归执行此操作,这可能会生成许多请求并挂起数据库服务器,这可以通过一些递归数据库方法来完成吗?

可视化: enter image description here 起始实体用箭头标记。 圈出所需的输出。

最佳答案

SQL Server 解决方案

我想主要问题是您需要先按 PR_ID 进行比较,然后再按 FP_ID 进行比较。所以在递归部分必须有一个CASE语句。在第一次运行中,我们通过 FP_ID 获取数据,在第二个运行中通过 PR_ID 等在模的帮助下获取数据。

DECLARE @fp int = 1

;WITH cte AS (
    SELECT  f.FP_ID,
            f.PR_ID, 
            1 as lev
    FROM #FP_PR f
    WHERE f.FP_id = @fp
    UNION ALL
    SELECT  f.FP_ID,
            f.PR_ID,
            lev+1
    FROM cte c
    CROSS JOIN #FP_PR f -- You can use INNER JOIN instead
    WHERE CASE (lev+1)%2 WHEN 0 THEN f.PR_ID WHEN 1 THEN f.FP_ID END = CASE (lev+1)%2 WHEN 0 THEN c.PR_ID WHEN 1 THEN c.FP_ID END
    AND NOT (f.PR_ID = c.PR_ID AND f.FP_ID = c.FP_ID)
)

SELECT *
FROM cte

输出:

FP_ID   PR_ID   lev
1       1       1
2       1       2
2       2       3
3       2       4
4       2       4

关于sql - 在多对多实体之间查找sql​​连接组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47307244/

相关文章:

c++ - 分离轴定理的实现不准确

sql - Yii2:如何将带有子查询的查询转换为事件记录?

c# - 在数据库中插入多条记录的最佳方法

sql-server - 如何查找表中的行大小

python - 比较列表中整数与给定值的差异

java - 从数组创建二叉树

mysql - 如何从多个表中删除重复的外键?

sql - 一个(稍微复杂的)SQL 查询?

sql - 如何在postgresql中插入循环

c# - identity_insert 对元数据表的使用是否良好