我认为这将更容易解释为故事而不是示例代码。
我正在尝试在SQL中抓取此表并获取所有关系。
以下是关系如何发挥作用的项目符号示例。
o 6220 (Top Level Parent)
- 6219 (Child1 of 6220)
- 6221 (Child2 of 6220)
* 6222 (Child1 of 6221/GrandChild1 of 6220)
* 6223 (Child2 of 6221/GrandChild2 of 6220)
x 6224 (Child1 of 6223/GrandChild1 of 6221/GreatGrandChild1 of 6220)
o 6225 (Top Level Parent)
以下是表格形式:
Parent, Child
NULL, 6220
6220, 6221
6220, 6219
6221, 6222
6221, 6223
6223, 6224
NULL, 6225
我正在寻找的结果(最佳)是:
Parent, Child, Level
6220, 6220, 0
6220, 6221, 1
6220, 6219, 1
6220, 6222, 2
6220, 6223, 2
6220, 6224, 4
6221, 6222, 1
6221, 6223, 1
6221, 6224, 2
6223, 6224, 1
6225, 6225, 0
我已经尝试了递归CTE和循环,我可以接近但不完全。希望接近这个或类似的东西是有道理的。我想把它放到一张桌子里,我可以查询一下,找到父母或孩子的所有父母,祖父母,子女,孙子女等。兄弟姐妹关系并不重要。
谢谢你的期待。如果我能澄清,请告诉我。
以下是我尝试这样做的方式:
DECLARE @InsertedCount INT
DECLARE @RelationshipLevel TINYINT
DECLARE @AgyCount INT
DECLARE @LoopCount INT = 1
DECLARE @AgencyId INT
SELECT @AgyCount = COUNT(AgencyId) FROM dbo.Agency AS A
/* ==============================================================================
Get All AgencyIDs into a table with an incremented column
============================================================================== */
IF (OBJECT_ID('tempdb.dbo.#tmpAllAgy') > 0)
DROP TABLE #tmpAllAgy
CREATE TABLE #tmpAllAgy (tmpAllAgyId INT IDENTITY(1,1) PRIMARY KEY, AgencyId INT)
INSERT INTO #tmpAllAgy (AgencyId)
SELECT AgencyId FROM dbo.Agency ORDER BY AgencyId
/* ==============================================================================
Temp table for the results of the matrix to compare to physical table
============================================================================== */
IF (OBJECT_ID('tempdb.dbo.#ChildAgencies') > 0)
DROP TABLE #ChildAgencies
CREATE TABLE #ChildAgencies (LoopOrder INT, ParentAgencyId INT, ChildAgencyId INT, RelationshipLevel TINYINT)
/* ==============================================================================
Outer loop to get the next Agency Id from Temp Table
============================================================================== */
WHILE @LoopCount <= @AgyCount
BEGIN
SET @RelationshipLevel = 0
SELECT @AgencyId = AgencyId FROM #tmpAllAgy WHERE tmpAllAgyId = @LoopCount
INSERT INTO #ChildAgencies(LoopOrder, ParentAgencyId, ChildAgencyId, RelationshipLevel)
SELECT @LoopCount, NULL, AgencyId, @RelationshipLevel
FROM dbo.Agency
WHERE AgencyId = @AgencyID
SET @InsertedCount = 1--@@ROWCOUNT
/* ==============================================================================
Inner loop to create the hierarchy for each AgencyId
============================================================================== */
WHILE @InsertedCount > 0
BEGIN
SET @InsertedCount = NULL
SET @RelationshipLevel = @RelationshipLevel + 1
INSERT INTO #ChildAgencies (LoopOrder, ParentAgencyId, ChildAgencyId, RelationshipLevel)
SELECT @LoopCount, @AgencyId, AgencyId, @RelationshipLevel
FROM dbo.Agency
WHERE AgencyId NOT IN (SELECT ChildAgencyId FROM #ChildAgencies)
AND ParentAgencyId IN (SELECT ChildAgencyId FROM #ChildAgencies)
AND StatusCode <> 109 /*QA-Deleted*/
SET @InsertedCount = @@ROWCOUNT
END
SET @LoopCount = @LoopCount + 1
END
递归CTE似乎只会带来直接的父母和孩子,同时随意增加计数。 上面的循环代码很接近,但似乎以奇怪的顺序做事。
答案 0 :(得分:1)
开始时有点难以理解,但你需要的只是尝试更多。 我从MSDN获得了一个例子
http://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx
并设法使用广告SQLFiddle,只删除了一些“胖”
希望它能帮助你
答案 1 :(得分:1)
我相信你提出的建议是不可能使用SQL查询。从理论上讲,你的人际关系可能有周期。您基本上是在SQL表中实现图形,因为兄弟姐妹是可能的。假设6221是6222的父母,6222是6223的父母,6223是6221的父母?然后你有一个周期。
如果保证不存在这样的结构,那么在最坏的情况下你仍然有一个完全连接的图形来处理。是否有最大的“年龄差异”?如果是这样,那么你可以只使用有限数量的连接来实现这一点,使用外部连接来确保那些没有关系的人仍然被包括在内。对于关系的每个“级别”,您必须执行三个连接:一个用于父级,一个用于兄弟级,一个用于子级。您还需要确保不会遍历回原始节点。
简而言之,假设没有循环,您将在包含树林的表中实现树遍历。我不知道你怎么能在SQL中做到这一点。您可以使用编程语言,也可以使用循环作为存储过程,但只有在没有循环的情况下,或者以某种方式实现循环检测。
祝你好运。
编辑:此外,除非您获得树根(顶级节点),否则树中的任何节点都可以被视为根。如果基本图是有向图,但是(父子关系是显式的)则根是没有父对象的节点。对于具有已定义根和有限深度的N-Ary树,您可以实现任何标准图搜索算法,遍历成本为1,直到所有节点都有与之关联的成本。有广度优先搜索,深度搜索,最佳优先搜索,A *等。
编辑: 尝试这样的事情:
create procedure update_node_depths
as
begin
set nocount on
update nodes
set depth = null
update nodes
set depth = 0
where parent_id is null
while exists (select node_id from nodes where depth is null)
begin
update nodes
set depth = (select n2.depth+1
from nodes n2
where n2.node_id = nodes.parent_id)
where parent_id in (select node_id
from nodes n3
where n3.depth is not null)
end
select *
from nodes
end
go
然后,您可以执行此类操作来获取表格,并在执行此操作时自动更新深度。
execute update_node_depths
go
答案 2 :(得分:0)
从基本案例开始:Parent
值为NULL
的人总是 Level
0
。这意味着您可以更新Parent is NULL
的每一行并设置Level = 0
。
下一步:查找父母的Level
值为not NULL
的行。将其更新为Level
值= parent.Level + 1
。
重复上述步骤,直到表格的每一行都有Level
值。
答案 3 :(得分:0)
所以,我终于有了一些工作要做。这和我一直在做的几乎一样。而不是循环中的循环,我采用了内循环并使其成为一个函数。然后我创建了一个循环的SP,并一次向该函数提供一个ID,并将结果附加到临时表。
这里基本上是内循环:
DECLARE @AgencyId INT = 6220
DECLARE @InsertedCount INT
DECLARE @LevelCount INT = 0
CREATE TABLE #ChildAgencies(AgencyId INT, LevelCount INT)
INSERT INTO #ChildAgencies(AgencyId, LevelCount)
SELECT AgencyId, @LevelCount
FROM dbo.Agency
WHERE AgencyId = @AgencyId
SET @InsertedCount = @@ROWCOUNT
WHILE @InsertedCount > 0
BEGIN
SET @InsertedCount = NULL
SET @LevelCount = @LevelCount + 1
INSERT INTO #ChildAgencies(AgencyId, LevelCount)
SELECT AgencyId, @LevelCount
FROM dbo.Agency
WHERE AgencyId NOT IN (SELECT AgencyId FROM #ChildAgencies)
AND ParentAgencyId IN (SELECT AgencyId FROM #ChildAgencies)
AND StatusCode <> 109 /*QA-Deleted*/
SET @InsertedCount = @@ROWCOUNT
END
产生:
AgencyId LevelCount
6220 0
6219 1
6221 1
6222 2
6223 2
6224 3
显然,我没有在最终产品中默认@AgencyId变量。我在存储过程中设置@AgencyId并将其传递给它。