有一张表,包含ID和Parent ID,也就是说,其中一条数据的ID可能会作为另一条数据的Parent ID出现。
现在我想查询出和一个指定ID有联系的所有数据,不管是父节点的兄弟节点,还是它的子节点,或它的子节点的子节点,兄弟节点的子节点,等等。
例如:
table:test
ID Parent ID
1 5
2 1
3 2
4 1
5 -
6 5
7 -
8 4
9 -
10 6
当指定的ID是1,2,3,4,5,6,8,10任意一个的时候,那么这几条数据都应该被查询出来。(因为需要查询出所有有联系的数据,不管是子节点还是父节点还是兄弟节点甚至是延伸出来的数据,都应该被查询出来)
当ID是9的时候就只有一条ID为9的数据。
这个查询能否使用一条SQL语句就实现了呢?这是一个函数来实现的,这个函数可以多次执行SQL以便完善SQL语句,但是最终还是需要仅仅一条SELECT语句能得到一个完整的结果集。
请大家帮帮忙,非常感谢。
(目前我的方法是使用迭代的方法,不断地增加SQL语句中的where子语句以便获取所有数据,但是这个方法有一个限制,SQL语句的长度是有限制的,所以希望大家能想想起他方法)
现在都些什么人,不仔细回答就不要乱拷贝,有什么意思。
你的问题1个SQL应该实现不了,不过这样就行了,也很简单,你可以多些数据测测,如果有其他更好的方法可以告诉我
---------------------建立 Temporarily 临时表----------------------------
DECLARE @Temporarily TABLE (Temporarilyid int, TemporarilyPId int)
---------------------申明临时变量a,b,存储你的第一个查询条件,这个固定----------------------------
DECLARE @a int
set @a=(SELECt ID1 as a FROM test WHERe ID1 = 1)
DECLARE @b int
set @b=(SELECt ParentID as b FROM test WHERe ID1 = 1)
---------------------将第一条结果插入临时表----------------------------
INSERT INTO @Temporarily VALUES (@a,@b)
---------------------循环执行,循环数为你记录的条数,这个不固定----------------------------
DECLARE @i int
SET @i = 1
WHILE @i <= 10
BEGIN
---------------------临时变量e,返回表的某条数据是否符合你的子父关联要求----------------------------
DECLARE @e int
set @e=(SELECt distinct Temporarilyid as e FROM @Temporarily WHERe Temporarilyid IN(SELECt ParentID FROM test WHERe ID1 = @i) or TemporarilyPId in(SELECt ID1 FROM test WHERe ID1 = @i))
---------------------符合,执行插入操作----------------------------
IF @e>0
BEGIN
set @a=(SELECt ID1 as c FROM test WHERe ID1 = @i)
set @b=(SELECt ParentID as d FROM test WHERe ID1 = @i)
INSERT INTO @Temporarily VALUES (@a,@b)
END
SET @i = @i + 1
END
---------------------显示结果集----------------------------
SELECt Temporarilyid AS a,TemporarilyPId AS b FROM @Temporarily
觉对可以满足你说的要求,多少条数据都可以,具体说一条sql语句执行,我还没想到可以的
出现这种情况 是数据库设计的不好。假如能修改数据库的话会给你带来很大的方便
增加一个字段 字段中就保存上层级关系 例如
1
1-1
1-1-1
1-1-1-1
1-1-2
1-2
1-3
无论你选中 哪个节点,要得到他的所有儿子 只需要 like 节点+'-%'即可得到,而改变此表结构工作量也不是很大,你只用在增加节点位置多修改这个字段的值即可。
如果不修改表结构 就只能用上述方法,递归或者循环了。虽然 递归循环可以得到相同结果但是效率并不理想
楼上那个方法是oracle的start with ... connect by ...,SQL中没有这个关键字
可以看看下面的资料,希望对你有用
SQL Sever 联机丛书:
访问和更改关系数据
展开层次结构
数据库经常存储层次信息。例如,下面的数据是全球一些地区的层次表示形式。这种表示形式并未清楚地显示出数据中隐含的结构。
Parent Child
---------------------------------- ----------------------------------
World Europe
World North America
Europe France
France Paris
North America United States
North America Canada
United States New York
United States Washington
New York New York City
Washington Redmond
而下面的示例则更容易解释:
World
North America
Canada
United States
Washington
Redmond
New York
New York City
Europe
France
Paris
下面的 Transact-SQL 过程将一个编码的层次展开到任意深度。尽管 Transact-SQL 支持递归,但是使用临时表作为堆栈来跟踪所有正在处理中的项目(已经开始但尚未结束),将更加有效。某个项目一旦处理完毕,将被从堆栈中删除。当发现新的项目时,这些项目将被添加到堆栈中。
CREATE PROCEDURE expand (@current char(20)) as
SET NOCOUNT ON
DECLARE @level int, @line char(20)
CREATE TABLE #stack (item char(20), level int)
INSERT INTO #stack VALUES (@current, 1)
SELECt @level = 1
WHILE @level > 0
BEGIN
IF EXISTS (SELECT * FROM #stack WHERe level = @level)
BEGIN
SELECt @current = item
FROM #stack
WHERe level = @level
SELECt @line = space(@level - 1) + @current
PRINT @line
DELETE FROM #stack
WHERe level = @level
AND item = @current
INSERT #stack
SELECt child, @level + 1
FROM hierarchy
WHERe parent = @current
IF @@ROWCOUNT > 0
SELECT @level = @level + 1
END
ELSE
SELECT @level = @level - 1
END -- WHILE
输入参数 (@current) 表示层次中的开始位置。它还跟踪主循环中的当前项目。
使用的两个局部变量分别是 @level(用于跟踪层次结构中的当前级别)和 @line(是用于构造缩进行的工作区)。
SET NOCOUNT ON 语句避免输出中夹杂每个 SELECT 产生的 ROWCOUNT 消息。
使用层次中开始点的项目标识符来创建和整理临时表 #stack,而 @level 被设置为与之匹配。#stack 中的 level 列允许同一个项目出现在数据库的多个级别中。虽然这种情况不适用于该示例中的地理数据,但是它可以用于其它示例。
在下面的示例中,当 @level 大于 0 时,该过程执行以下步骤:
如果当前级别 (@level) 的堆栈中有任何项目,该过程将选择其中一个,并称之为 @current。
缩进项目 @level 空格,然后打印该项目。
从堆栈中删除该项目以免重复处理它,然后将其所有子项目添加到堆栈的下一级 (@level + 1) 中。这是唯一使用层次表 (#stack) 的地方。
如果使用传统的编程语言,就必须找到每个子项目并将其逐个添加到堆栈中。而使用 Transact-SQL,只用一个语句就能找到并添加所有的子项目,以免又使用一个嵌套循环。
如果有子项目 (IF @@ROWCOUNT > 0),则下降一级处理它们 (@level = @level + 1);否则,继续在当前级别上处理。
最后,如果在当前级别的堆栈中没有待处理的项目,则返回到上一级,看上一级是否有待处理的项目 (@level = @level - 1)。当再没有上一级时,则展开完毕。
比如ID是9的时候:
select * from table start with ID = 9 connect by prior Parent ID= ID;