Select/删除三自引用多对多关系SQL查询

Select / Delete of Three self referencing many to many relationships SQL Query

我有一个 table ProjectLayerContent 设计如下:

  1. ProjectLayerContentID [INT]
  2. ProjectLayerContentName [NVARCHAR(200)]
  3. ProjectLayerContentParentID [INT]
  4. ScopeIsProjectLayerContent [位]
  5. ScopeIsProjectLayerContentID [INT]
  6. DataTypeIsContentOfContent [位]
  7. ContentOfContentID [INT]

    • 项目图层内容可能有父级,也可能没有,子级也一样。
    • 项目层内容范围可能包括另一个项目层内容。
    • 项目图层内容数据类型可能是其他内容的类型。

我想做的是在删除过程中,我想显示一个列表,其中包含如果您要删除此项目层内容将要删除的内容的计数。 这几乎就是我遇到的问题,但我知道这些结果是不正确的

    DECLARE @ProjectLayerContentID INT = 1;
DECLARE @resTable TABLE (
    ProjectLayerContentIDP int,
    ProjLContentType nvarchar(100));

    DECLARE @ProjectLayerContentIDRecursionParam int;
    DECLARE @Type NVARCHAR(MAX);

    DECLARE @resultString NVARCHAR(MAX) = '';

    -- SELECT Project layer content children with recursion

-- SELECT the count of the result from the recursion of the children of the project layer content id passed with the sql parameter in the query
        DECLARE ProjectLayerContentChildren_Cursor CURSOR FOR
        SELECT  ProjectLayerContentID, 'Child(ren)'
        FROM    ProjectLayerContent
        WHERE   ProjectLayerContentParentID = @ProjectLayerContentID

        OPEN ProjectLayerContentChildren_Cursor
        FETCH NEXT FROM ProjectLayerContentChildren_Cursor INTO @ProjectLayerContentIDRecursionParam, @Type
                WHILE @@FETCH_STATUS = 0
                    BEGIN
                        INSERT INTO @resTable SELECT @ProjectLayerContentIDRecursionParam, @Type;
                        ;WITH ProjectLayerContentTotalScopeChildren AS(
                        SELECT  ProjectLayerContentID,CAST('Content(s) of Child(ren)' as varchar(259))   AS ProjLContentType
                        FROM    ProjectLayerContent
                        WHERE   ContentOfContentID = @ProjectLayerContentIDRecursionParam
                        UNION ALL
                        SELECT  Scopechildren.ProjectLayerContentID, CAST('Children Content Of Content of Child(ren)' as varchar(259)) AS ProjLContentType
                        FROM    ProjectLayerContent Scopechildren INNER JOIN
                                ProjectLayerContentTotalScopeChildren projLContents ON Scopechildren.ContentOfContentID = projLContents.ProjectLayerContentID
                        UNION ALL
                        SELECT  children.ProjectLayerContentID, CAST('Child(ren) of Child(ren) of Child(ren)' as varchar(259)) AS ProjLContentType
                        FROM    ProjectLayerContent children INNER JOIN
                                ProjectLayerContentTotalScopeChildren projLContents ON children.ProjectLayerContentParentID = projLContents.ProjectLayerContentID
                        )
                        INSERT INTO @resTable SELECT ProjectLayerContentID, ProjLContentType from ProjectLayerContentTotalScopeChildren
                                            FETCH NEXT FROM ProjectLayerContentChildren_Cursor INTO @ProjectLayerContentIDRecursionParam, @Type
                END
        -- close the cursor
        CLOSE ProjectLayerContentChildren_Cursor
        DEALLOCATE ProjectLayerContentChildren_Cursor


    -----------------------------------------------------------------------------------------------------------
        -- SELECT Project layer content Scope children with recursion
        DECLARE ProjectLayerContent_Cursor CURSOR FOR
        SELECT  ProjectLayerContentID, 'Content Of Content'
        FROM    ProjectLayerContent
        WHERE   ContentOfContentID = @ProjectLayerContentID


        OPEN ProjectLayerContent_Cursor
        FETCH NEXT FROM ProjectLayerContent_Cursor INTO @ProjectLayerContentIDRecursionParam, @Type
                WHILE @@FETCH_STATUS = 0
                    BEGIN
                            INSERT INTO @resTable SELECT @ProjectLayerContentIDRecursionParam, @Type;
                            ;WITH ProjectLayerContentTotalScopeContentOfContent AS(
                            SELECT  ProjectLayerContentID,CAST('Children Content Of Content' as varchar(259))   AS ProjLContentType
                            FROM    ProjectLayerContent
                            WHERE   ContentOfContentID = @ProjectLayerContentIDRecursionParam
                            UNION ALL
                            SELECT  Scopechildren.ProjectLayerContentID, CAST('Children Content Of Content of Children Content Of Content' as varchar(259)) AS ProjLContentType
                            FROM    ProjectLayerContent Scopechildren INNER JOIN
                                    ProjectLayerContentTotalScopeContentOfContent projLContents ON Scopechildren.ContentOfContentID = projLContents.ProjectLayerContentID
                            UNION ALL
                            SELECT  children.ProjectLayerContentID, CAST('Children of Children Content Of Content' as varchar(259)) AS ProjLContentType
                            FROM    ProjectLayerContent children INNER JOIN
                                    ProjectLayerContentTotalScopeContentOfContent projLContents ON children.ProjectLayerContentParentID = projLContents.ProjectLayerContentID
                            )
                            INSERT INTO @resTable SELECT ProjectLayerContentID, ProjLContentType from ProjectLayerContentTotalScopeContentOfContent
                                                FETCH NEXT FROM ProjectLayerContent_Cursor INTO @ProjectLayerContentIDRecursionParam, @Type
                END
        -- close the cursor
        CLOSE ProjectLayerContent_Cursor
        DEALLOCATE ProjectLayerContent_Cursor

        --select the result to present it.
        SELECT * FROM @resTable;

提前致谢。

我发现这个解决方案可以根据需要获得所需的功能。

我首先创建了存储过程来获取此项目层的所有 children,然后创建了一个 table 来添加结果。因为应用此解决方案的第一个错误是如果您有一系列相互调用的存储过程,则 INSERT INTO EXEC 将不起作用。只在第一次有效,其他次数都会报错。​​

DECLARE @ProjectLayerContentID INT = 1;
DECLARE @ProjectLayerContentIDRecursionParam INT;
DECLARE @Type NVARCHAR(MAX);

DECLARE @resultString NVARCHAR(MAX) = '';

-------Create temp table to insert the results into it
CREATE TABLE #ResTable(
ProjectLayerContentIDP int,
ProjLContentType nvarchar(100));

然后我为所有child人的select语句创建了一个游标,这些child人与这个项目层有child的关系,或者是它的内容。

-- SELECT Project layer content children with recursion

-- SELECT the count of the result from the recursion of the children of the project layer content id passed with the sql parameter in the query

DECLARE ProjectLayerContent_Cursor CURSOR FOR
SELECT  ProjectLayerContentID, CASE WHEN ProjectLayerContentParentID = @ProjectLayerContentID THEN 'Child(ren)' ELSE 'Content(s) of Content(s)' END
FROM    ProjectLayerContent
WHERE   ProjectLayerContentParentID = @ProjectLayerContentID
        OR ContentOfContentID = @ProjectLayerContentID

OPEN ProjectLayerContent_Cursor
FETCH NEXT FROM ProjectLayerContent_Cursor INTO @ProjectLayerContentIDRecursionParam, @Type
        WHILE @@FETCH_STATUS = 0
            BEGIN
                INSERT INTO #ResTable SELECT @ProjectLayerContentIDRecursionParam, @Type;

然后我会调用递归存储过程获取当前项目层的每一个内容chlidren,以及children.

的内容
Exec DeleteCheck_ProjectLayerContentChildren @ProjectLayerContentIDRecursionParam;
                    FETCH NEXT FROM ProjectLayerContent_Cursor INTO @ProjectLayerContentIDRecursionParam, @Type
                END
    -- close the cursor
    CLOSE ProjectLayerContent_Cursor
    DEALLOCATE ProjectLayerContent_Cursor

在这部分,我们将 select 结果,然后从数据库服务器中删除临时文件 table。

        --select the result to present it.
SELECT @resultString =  @resultString + '<br/><u>' + CONVERT(NVARCHAR(MAX), Count(ProjectLayerContentIDP)) + '</u> ' + ProjLContentType
FROM #ResTable
GROUP BY ProjLContentType;
SELECT @resultString;
DROP TABLE #ResTable

这是我们在之前的查询中调用的递归存储过程

CREATE PROCEDURE  [dbo].[DeleteCheck_ProjectLayerContentChildren]
    @ProjectLayerContentID INT
AS
BEGIN

    DECLARE @ProjectLayerContentIDRecursionParam INT;
    DECLARE @Type NVARCHAR(MAX);

    -- SELECT Project layer content children with recursion

-- SELECT the count of the result from the recursion of the children of the project layer content id passed with the sql parameter in the query.

注意这里我们在游标的减速中加入了Local,因为创建同名游标会报错

        DECLARE ProjectLayerContentChildren_Cursor CURSOR LOCAL FOR
        SELECT  ProjectLayerContentID, CASE WHEN ProjectLayerContentParentID = @ProjectLayerContentID THEN 'Child(ren) of Child(ren)' ELSE 'Child(ren) Content(s) of Content(s)' END
        FROM    ProjectLayerContent
        WHERE   ProjectLayerContentParentID = @ProjectLayerContentID
                OR ContentOfContentID = @ProjectLayerContentID

这个查询的大部分内容与上一个查询相同,但这是针对项目层内容 children of children counts,我们不创建result table 因为它已经创建了,那么我们只需添加结果,我们就有了需要的功能,你可以将它应用于两个或三个以上的自我关系。

OPEN ProjectLayerContentChildren_Cursor
            FETCH NEXT FROM ProjectLayerContentChildren_Cursor INTO @ProjectLayerContentIDRecursionParam, @Type
                    WHILE @@FETCH_STATUS = 0
                        BEGIN
                            INSERT INTO #ResTable SELECT @ProjectLayerContentIDRecursionParam, @Type;
                            Exec DeleteCheck_ProjectLayerContentChildren @ProjectLayerContentIDRecursionParam
                            FETCH NEXT FROM ProjectLayerContentChildren_Cursor INTO @ProjectLayerContentIDRecursionParam, @Type
                        END
            -- close the cursor
            CLOSE ProjectLayerContentChildren_Cursor
            DEALLOCATE ProjectLayerContentChildren_Cursor
    END