选择/删除三个自引用多对多关系的SQL查询

时间:2018-04-13 13:25:15

标签: tsql sql-server-2012 recursive-query database-cursor

我有一个表ProjectLayerContent设计如下:

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

    • 项目图层内容可能包含父项,也可能没有。对于子项也是如此。
    • 项目图层内容范围可能包含其他项目图层内容。
    • 项目图层内容数据类型可能是另一种内容的类型。
  8. 我想要做的是在删除过程中,我想显示一个列表,其中包括如果要删除此项目图层内容将删除的内容。 这几乎就是我所涉及的,但我知道这些结果并不正确

        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;
    

    提前致谢。

1 个答案:

答案 0 :(得分:0)

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

我创建了存储过程以首先获取此项目图层的所有子项,并创建了一个表来添加结果。因为如果您有一个INSERT INTO EXEC,那么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));

然后我为所有孩子的select语句创建了一个游标,这个孩子的关系是该项目图层的子项,或者是它的内容。

-- 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和子项的内容。

Exec DeleteCheck_ProjectLayerContentChildren @ProjectLayerContentIDRecursionParam;
                    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 @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

这个查询的大部分内容与前一个查询相同,但这是针对项目图层内容子项的子项计数,我们不再创建结果表,因为它已经创建,然后我们只需添加结果,我们就拥有了所需的功能,您可以将它应用于两三个以上的自我关系。

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