2015-05-05 21 views
7

Sto provando a scrivere una procedura memorizzata per una ricerca per parola chiave. Il modo in cui abbiamo impostato il nostro DB.Come inner inner join multiple columns?

C'è un tavolo Genres che ha Genre names e Genre ID's, poi c'è un tavolo Genrebridge che ha genreID1, GenreID2, GenreID3, GenreID4, GenreID5, SongID, AlbumID e ArtistID.

Come posso INNER JOIN ognuno dei campi GenreID, in modo che il Genre name è legata al Genre Bridge tavolo

ALTER PROCEDURE [dbo].[usp_album_search_keyword_AlbumNameANDArtistName] 
(
    -- Add the parameters for the stored procedure here 
    @albumname varchar(255), 
    @artistname varchar(255) 
) 
As 
Begin 
Select 
    Distinct a.AlbumTitle, art.ArtistName, a.AvgRatingNBR, a.OriginalPrice, a.DiscountPrice 
FROM 
    Albums a 
    inner join Artists art on a.ArtistID = art.ArtistID 
    inner join GenreBridge gb on gb.AlbumID = a.AlbumID 
    inner join Genres g on g.GenreID = gb.GenreID1 
    inner join genres g on g.GenreID = gb.genreID2 
    inner join genres g on g.GenreID = gb.GenreID3 
    inner join genres g on g.GenreID = gb.GenreID4 
    inner join genres g on g.GenreID = gb.GenreID5 

    where a.AlbumTitle like '%' + @albumname + '%' 
    and art.ArtistName like '%' + @artistname + '%' 
End 
+0

Questo codice funziona? E se sì, quale risultato ottieni? –

+0

quando provo ed eseguo la procedura ottengo il seguente errore: Nome oggetto "g" non valido. modifica: credo che sia la seconda volta che dichiaro i generi come g – Parth

+4

utilizzare diversi alias invece di 'g', come' g1', 'g2', ecc. – cha

risposta

5

Altro che utilizzando gli stessi alias come notato nei commenti, la tabella GenreBridge non è correttamente normalizzata. Per normalizzare la tabella, sarebbe meglio avere una singola colonna GenreID sulla tabella e quindi inserire tutte le righe necessarie per modellare tutti i generi di un album. Ciò eleverà anche la restrizione arbitraria sul numero di generi per album.

Come nota a margine, la procedura originale non sembra utilizzare lo Genre (nell'elenco di selezione o di filtro), quindi non è necessario unirsi a esso e non è necessario lo DISTINCT.

Come hai notato, si trovano ora ad affrontare i problemi con si unisce a seconda del numero di colonne di genere validi presenti sul AlbumGenre

Supponendo che hai usato le chiavi primarie INT tutto, vorrei normalizzare il tavolo GenreBridge di essere un molti: molti tabella di collegamento tra album e generi, e allo stesso tempo rinominarlo AlbumGenre per riflettere meglio i tanti: molti convenzione, ad esempio:

CREATE TABLE dbo.AlbumGenre 
(
    AlbumId INT NOT NULL, 
    GenreId INT NOT NULL, 

    CONSTRAINT PK_AlbumnGenre PRIMARY KEY(AlbumId, GenreId), 
    CONSTRAINT FK_AlbumnGenre_Albumn FOREIGN KEY(AlbumId) REFERENCES Albums(AlbumId), 
    CONSTRAINT FK_AlbumnGenre_Genre FOREIGN KEY(GenreId) REFERENCES Genres(GenreId) 
); 

la restrizione che ci può essere tra 1 e 5 generi dovranno essere applicato dal tuo programma (cioè prima di inserire uno AlbumnGenre collegamento di registrazione, in modo che ci sono meno di 5 righe per questo albumn.)

Per elencare tutti i generi di un album, si avrebbe solo bisogno di unirsi Albumn al AlbumGenre e filtro AlbumnId nella clausola in cui (lo farà restituisce tante righe quanti sono i generi).

Come accennato, senza bisogno di DISTINCT o unirsi a Genere:

ALTER PROCEDURE [dbo].[usp_album_search_keyword_AlbumNameANDArtistName] 
(
    -- Add the parameters for the stored procedure here 
    @albumname varchar(255), 
    @artistname varchar(255) 
) 
As 
Begin 
Select a.AlbumTitle, art.ArtistName, a.AvgRatingNBR, a.OriginalPrice, a.DiscountPrice 
FROM 
    Albums a 
    inner join Artists art on a.ArtistID = art.ArtistID 
    where a.AlbumTitle like '%' + @albumname + '%' 
    and art.ArtistName like '%' + @artistname + '%' 
End 
+0

quindi avrei bisogno di avere 3 tabelle ponte separate in questo scenario, corretto? – Parth

+0

No, solo la tabella 'AlbumGenre'. Se un album ha 3 generi, allora ci saranno 3 righe in 'AlbumGenre' per lo stesso' AlbumId'. Unire 'una volta' tra 'Album' e' AlbumGenre' e 'Genere' e filtrare per' Album.AlbumId' genererà 3 righe. – StuartLC

+0

scusa, la mia domanda era vaga. @stuartLC, credo che avrei bisogno di creare una tabella SongGenre e una tabella ArtistGenre nel mio db e collegare in modo simile come descritto sopra, In precedenza stavo provando ad avere una tabella bridge con questi campi: GenreID \t SongID \t AlbumID \t ArtistID. Questo cattivo design db? – Parth

1

@StuartLC dà qualche buon feedback che vorrei prendere in seria considerazione. Ma se hai intenzione di lasciare lo schema del tuo database così com'è, allora questa query dovrebbe funzionare:

SELECT   a.AlbumTitle, 
       art.ArtistName, 
       a.AvgRatingNBR, 
       a.OriginalPrice, 
       a.DiscountPrice, 
       g1.GenreName, 
       g2.GenreName, 
       g3.GenreName, 
       g4.GenreName, 
       g5.GenreName 
FROM   Albums a 
INNER JOIN  Artists art on a.ArtistID = art.ArtistID 
INNER JOIN  GenreBridge gb on gb.AlbumID = a.AlbumID 
LEFT OUTER JOIN Genres g1 on g1.GenreID = gb.GenreID1 
LEFT OUTER JOIN Genres g2 on g2.GenreID = gb.GenreID2 
LEFT OUTER JOIN Genres g3 on g3.GenreID = gb.GenreID3 
LEFT OUTER JOIN Genres g4 on g4.GenreID = gb.GenreID4 
LEFT OUTER JOIN Genres g5 on g5.GenreID = gb.GenreID5 
WHERE   a.AlbumTitle like ('%' + @albumname + '%') 
    AND   art.ArtistName like ('%' + @artistname + '%') 
+1

grazie Raj! Ho appena finito di discuterne con il mio gruppo, seguiremo il modello di @ stuartLC e normalizzeremo il tavolo. – Parth