Select/删除三自引用多对多关系SQL查询
Select / Delete of Three self referencing many to many relationships SQL Query
我有一个 table ProjectLayerContent 设计如下:
- ProjectLayerContentID [INT]
- ProjectLayerContentName [NVARCHAR(200)]
- ProjectLayerContentParentID [INT]
- ScopeIsProjectLayerContent [位]
- ScopeIsProjectLayerContentID [INT]
- DataTypeIsContentOfContent [位]
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
我有一个 table ProjectLayerContent 设计如下:
- ProjectLayerContentID [INT]
- ProjectLayerContentName [NVARCHAR(200)]
- ProjectLayerContentParentID [INT]
- ScopeIsProjectLayerContent [位]
- ScopeIsProjectLayerContentID [INT]
- DataTypeIsContentOfContent [位]
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