sql select query self join或loop through来获取记录

时间:2014-05-05 10:31:38

标签: sql sql-server sql-server-2008

我在sql server中有这种情况我有一个名为Room的表,这里是它的数据,我想要输出这样的图片,如图所示我试图显示我的表名为room然后在上面我已经放置了标签输入,其中包含RoomIdConnectingRoomID以及更多其他列现在我想要的是一个sql select查询,它可以返回我放置标签名称输出的场景..

enter image description here

这些价​​值是自我创造的我有数以千计的房间和房间的桌子和千间连通房希望我的问题很清楚,谢谢。

5 个答案:

答案 0 :(得分:2)

我认为你可以使用它:

with x as (
    select *, sum(case connectingroomid when 0 then 1 else 0 end) over(order by roomid) as grp
    from rooms
)
select x.roomid, (select min(x2.roomid) as min_roomid from x x2 where x2.grp = x.grp) as connectingroomid
from x

答案 1 :(得分:1)

这是一个递归查询:所有房间都会进入连通房,直到找到没有连通房的连接房间(即房间连接ID为0)。

with rooms (roomid, connectingroomid) as 
(
  select 
    roomid,
    case when connectingroomid = 0 then 
      roomid 
    else 
      connectingroomid 
    end as connectingroomid
  from room
  where connectingroomid = 0
  union all
  select room.roomid, rooms.connectingroomid 
  from room
  inner join rooms on room.connectingroomid = rooms.roomid
) 
select * from rooms
order by connectingroomid, roomid;

这是SQL小提琴:http://www.sqlfiddle.com/#!3/46ed0/1

编辑:这是解释。而不是在评论中这样做,我在这里做的是为了更好的可读性。

WITH子句用于在此处创建递归。你看我把它命名为房间和我从房间里选择的房间。以下是阅读方法:从UNION ALL之前的部分开始。然后在UNION ALL之后递归执行该部分。因此,在UNION ALL之前,我只选择连接房间为零的记录。在您的示例中,您将显示每个房间的连接房间除了那些带有连接房间的房间,您可以自己展示房间。我在这里使用CASE来做同样的事情。但是现在我正在解释这个,我注意到,由于WHERE子句,connectroomid总是为零。因此,语句可以简化:

with rooms (roomid, connectingroomid) as 
(
  select 
    roomid,
    roomid as connectingroomid
  from room where connectingroomid = 0
  union all
  select room.roomid, rooms.connectingroomid 
  from room
  inner join rooms on room.connectingroomid = rooms.roomid
) 
select * from rooms
order by connectingroomid, roomid;

SQL小提琴:http://www.sqlfiddle.com/#!3/46ed0/2

在UNION ALL之前的部分,我发现两个房间没有连接房间。现在,对于找到的两个房间执行UNION ALL之后的部分。它选择了刚刚找到连通房的房间。然后它选择刚刚找到连通房的房间。等等,直到联合返回不再有房间。

希望这有助于理解查询。您可以在Internet上查找“recursive cte”以查找有关该主题的更多示例和说明。

答案 2 :(得分:0)

select RoomID,
  (Case when RoomID<=157 then 154
   else 158 end) ConnectingRoomID
from Input

答案 3 :(得分:0)

首先,您的输出不正确:房间154也应连接到0室: - )

您所追求的是表格所定义的关系的transitive closure。使用“vanilla”SQL获取此值是impossible。但是,有一些extensions到SQL可以使recursive queries成为可能。

例如,如果我有关系“graph”:

src | target 
-----+--------
  1 |      2
  2 |      3
  3 |      4
  5 |      6
  6 |      7

我可以用相同的字段定义一个新表“closure”:

WITH RECURSIVE closure (src, target) AS 
 (SELECT src, target FROM 
   graph 
     UNION
   SELECT graph.src, closure.target FROM graph, closure WHERE 
     graph.target = closure.src) 
 SELECT * FROM closure

请注意,“闭包”发生在它自己的定义中(这就是为什么这是一个递归查询)它使用原始图形作为“种子”,并通过添加距离越来越大的元组来增长(检查自己这样做)。

结果(它清楚地显示了关系如何增长):

 src | target 
-----+--------
   1 |      2
   2 |      3
   3 |      4
   5 |      6
   6 |      7
   1 |      3
   2 |      4
   5 |      7
   1 |      4

如果您只对无法进一步扩展的对感兴趣,就像在原始示例中一样,您可以向闭包表添加一个额外的字段“distance”,并使用GROUP BY子句仅保留最大对。

免责声明:我不在Windows上,并使用了postgres。 MS SQL应该以同样的方式工作。

答案 4 :(得分:0)

尝试下面的sql:

假设@input是你的输入表
注意:我在@input表中添加了一个ID列

declare @input table
(
 id int identity,
 RoomId int,
 ConnectingRoomId int
)

insert into @input
select 154,0 union all
select 155,154 union all
select 156,155 union all
select 157,156 union all
select 158, 0 union all
select 159, 158 union all
select 160, 159

**更新:删除联盟**  SQL:

select
 d.id,  
 d.roomId
 ,max(d.connectingRoomId) as ConnectingRoomId
 from
(
select 
    bb.id,
    bb.RoomId 
    ,b.RoomId as connectingRoomId
from @input b
right join
(
 select 
    a.id,
    a.RoomId,a.ConnectingRoomId
 from @input a

) bb on (b.id < bb.Id) or b.Id = bb.Id
where b.ConnectingRoomId = 0
) d
group by d.id, d.RoomId

/*
Result (OUTPUT TABLE)

id          roomId      ConnectingRoomId
----------- ----------- ----------------
1           154         154
2           155         154
3           156         154
4           157         154
5           158         158
6           159         158
7           160         158
*/