如何从指向同一个表中的实体的外键中获取所有实体,重复一遍?

时间:2016-06-13 20:03:11

标签: sql sql-server

我有一张电影桌,一部电影可以有一个previous_part。现在我想基于movie_id' 412331'使用星球大战电影获取图像中显示的所有电影。这可能是SQL(MsSQL / AzureSql)吗?

我很抱歉缺少信息,但我真的不知道如何开始用这个问题开始SQL查询。

movies

更新

创建了一个递归查询,但它只有在我给予启动它的电影时才有效(请参阅代码块中的WHERE Prev.previous_part = 412332)。所以在这个例子中,第五集将返回另外两部电影而第六集只会返回第七集。

With MovieList AS
    (SELECT Prev.movie_id, Prev.title, Prev.description, Prev.previous_part, 1 as PrevLevel
    FROM Movie as Prev
    WHERE Prev.previous_part = 412332

    UNION ALL

    SELECT Mov.movie_id, Mov.title, Mov.description, Mov.previous_part, ML.PrevLevel + 1
    FROM Movie as Mov
    INNER JOIN MovieList AS ML
    ON Mov.previous_part = ML.movie_id
    WHERE Mov.previous_part IS NOT NULL)
SELECT * FROM MovieList

3 个答案:

答案 0 :(得分:2)

这是您需要的递归CTE:

;with ml as (
--this is Anckor Query
select movie_id, title, previous_part
from movie where movie_id = 412325
union all
--this is Recursive Query
select m.movie_id, m.title, m.previous_part
from movie m
inner join ml on ml.previous_part = m.movie_id --link current prev to parent id
--if you want sequels instead of prev's change to m.previous_part = ml.movie_id
)
select * from ml

答案 1 :(得分:0)

@Igors comment是正确的递归查询,如果有多个级别的引用/层次结构,则可以使用递归公用表表达式。 Microsoft有一个很好的经理/员工示例。 https://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

这可能比你想要的更复杂但有点不清楚。

如果它只是一个参考级别意味着您不必匹配,那么一次又一次地匹配以找到您想要的所有内容,您可以使用自引用外部联接。

SELECT *
FROM
    dbo.movies m1
    LEFT JOIN dbo.movies m2
    ON m1.movied_id = m2.previous_part
WHERE
    m1.title LIKE '%Star Wars%'
    OR m2.movied_ID IS NOT NULL
    OR m2.title LIKE '%Star Wars%'
先生,我认为你很接近。没有你的数据集,它有点难以尝试,但这里是一个编辑,应该为您提供每个电影及其级别的完整列表。

;With MovieList AS (
    SELECT Prev.movie_id, Prev.title, Prev.description, Prev.previous_part, 1 as PrevLevel
    FROM Movie as Prev
    WHERE Prev.previous_part IS NULL

    UNION ALL

    SELECT Mov.movie_id, Mov.title, Mov.description, Mov.previous_part, ML.PrevLevel + 1
    FROM Movie as Mov
    INNER JOIN MovieList AS ML
    ON Mov.previous_part = ML.movie_id
)
SELECT * FROM MovieList

请注意,您可以在SELECT * FROM MovieList上添加where语句,以便在生成层次结构后限制列表。

答案 2 :(得分:0)

这似乎解决了你的问题。

select * 
into #t
from (
select 123 id,'xxx'nm,1234 pid
union all
select 1234, 'xl',12345
union all 
select 12345,'xlxl',123456
) x

declare @mid int = 123

select x.* from #t x
where x.id = @mid

union all

select y.* from #t x
left join #t y
on x.pid = y.id
where x.id = @mid

union all

select z.* from #t x
left join #t y
on x.pid = y.id
left join #t z
on y.pid = z.id
left join #t xx
on z.pid = xx.id
where x.id = @mid

union all

select xx.* from #t x
left join #t y
on x.pid = y.id
left join #t z
on y.pid = z.id
left join #t xx
on z.pid = xx.id
where x.id = @mid

此查询最多可以播放4部电影,但您可以按照逻辑添加更多电影。 它也只有在您按最早的电影ID搜索时才有效。 如果你需要它来搜索两种方式,这应该工作

declare @mid int = 12345

select distinct * from 
(
select x.* from #t x
where x.id = @mid

union all

select y.* from #t x
left join #t y
on x.pid = y.id or  x.id = y.pid
where x.id = @mid

union all

select z.* from #t x
left join #t y
on x.pid = y.id or x.id = y.pid
left join #t z
on y.pid = z.id or y.id = z.pid 
where x.id = @mid

union all

select xx.* from #t x
left join #t y
on x.pid = y.id  or x.id = y.pid
left join #t z
on y.pid = z.id or y.id = z.pid 
left join #t xx
on z.pid = xx.id or z.id = xx.pid
where x.id = @mid

) x