2016-06-13 4 views
0

Ich habe eine Filmtabelle und ein Film kann einen previous_part haben. Nun möchte ich zum Beispiel anhand von movie_id '412331' alle Filme wie auf dem Bild mit den Star Wars-Filmen gezeigt bekommen. Ist dies mit SQL (MsSQL/AzureSql) möglich?Wie erhalten Sie alle Entitäten von einem Fremdschlüssel, der auf eine Entität in derselben Tabelle verweist, wiederholend?

Es tut mir leid für den Mangel an Informationen, aber ich habe ehrlich gesagt keine Ahnung, wie man überhaupt eine SQL-Abfrage mit diesem Problem zu machen.

movies

Update:

Erstellt eine rekursive Abfrage, aber es funktioniert nur, wenn ich den Film geben, der es allen (siehe WHERE Prev.previous_part = 412332 im Codeblock) beginnt. In diesem Beispiel würde also Episode V die beiden anderen Filme wiedergeben und Episode VI würde nur Episode VII zurückgeben.

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 
+0

[rekursive Abfragen mit Common Table Expressions] (https://technet.microsoft.com /en-us/library/ms186243(v=sql.105).aspx]). – Igor

+0

Ich liebe, wie die Prequels existieren hier nicht :) Gegeben, Sie haben eine publication_year, obwohl, vielleicht möchten Sie ein Feld namens etwas wie 'Franchise', 'Familie', oder' series' stattdessen, und dann zeigen Sie einfach die Datensätze, die den gleichen Serienwert (falls vorhanden) in der Reihenfolge der Veröffentlichung haben. –

+0

@JoelCoehoorn Das Problem ist, dass ich mit einer bestehenden Datenbank arbeite, die so aufgebaut ist. Der Filmtisch hat sogar rund 380000 Datensätze. –

Antwort

2

Dieser CTE rekursive ist Sie brauchen:

;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 
0

@Igors Kommentar korrekt rekursive Abfragen, wenn es mehrere Bezugsebenen sind/Hierarchie Sie einen rekursiven allgemeinen Tabellenausdruck verwenden können. Microsoft hat ein gutes Beispiel für Manager/Mitarbeiter. https://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

Das kann viel komplizierter als das, was Sie suchen, ist es ein wenig unklar.

Wenn es nur eine Bezugsebene ist, die bedeutet, dass Sie nicht übereinstimmen müssen und dann wieder und wieder übereinstimmen müssen, um alles zu finden, was Sie wollen, können Sie einfach einen Self Referencing Outer Join verwenden.

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%' 

Gute erste Stich Ich denke, Sie sind in der Nähe. Ohne dein Dataset ist es ein bisschen schwer zu probieren, aber hier ist ein Schnitt, der dir eine vollständige Liste aller Filme und deren Level geben soll.

;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 

Hinweis können Sie eine Erklärung, wo auf Ihrer SELECT * FROM MovieList fügen Sie die Liste zu begrenzen, wie Sie wollen, nachdem Sie die Hierarchie generieren.

+0

Leider muss ich dann immer wieder übereinstimmen. –

+0

Der MS-Link wird Sie dorthin bringen, denken Sie an previous_part als Manager im Beispiel und movie_id als Employee. SQLauthority hat auch einen guten, vielleicht etwas leichter zu verdauenden Artikel zum selben Thema. http://blog.sqlauthority.com/2012/04/24/sql-server-introduction-to-hierarchical-query-using-a-recursive-cte-a-primer/ – Matt

+0

Ich habe es gefolgt, aber die aktuelle Abfrage Ich habe nur funktioniert, wenn die angegebene movie_id die erste der Franchise ist. Also die früheste movie_id. –

0

Dies scheint Ihre Frage zu lösen.

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 

Diese Abfrage zieht bis zu 4 Filme, aber Sie können mehr nach der Logik hinzufügen. auch funktioniert es nur, wenn Sie nach der frühesten Film-ID suchen. wenn Sie es brauchen beide Wege zu suchen, sollte dies

arbeiten
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 
Verwandte Themen