2016-03-10 3 views
3

У меня три таблицы: albums, songs и images. таблицы выглядят примерно так:MySQL условный LEFT JOIN?

albums стол:

id |  title  | image_id 
5 | First Album |  1 
6 | Another Album |  2 

songs стол:

id | album_id |  title  | image_id 
32 |  5  | My Song |  3 
33 |  5  | Another One |  4 
34 |  5  | First Song |  0 
35 |  6  | My Song #2 |  0 
36 |  6  | Fancy Title |  0 
37 |  6  | My Love Song |  5 

images стол:

id |  path 
1 | path/to/image1.jpg 
2 | path/to/image2.jpg 
3 | path/to/image3.jpg 
4 | path/to/image4.jpg 
5 | path/to/image5.jpg 

Я пытаюсь отобразить список песни с их т иглами и соответствующими изображениями.

Если у песен нет изображения (если image_id столбец 0), то я хочу просто использовать образ альбома.

Единственный код, который я до сих пор это, и я застрял:

SELECT songs.title, images.path 
FROM songs 
LEFT JOIN images 
ON images.id = songs.image_id 

// ...if songs.image_id is 0, i want to just use the image_id of the corresponding album instead 

Было бы хорошо, если бы это был эффективный запрос, который может работать с большими таблицами.

+0

Используйте [ 'COALESCE()'] (http://dev.mysql.com/doc/refman/5.7/en/comparison- operator.html # function_coalesce) –

+0

По производительности, возможно, лучше использовать NULL вместо 0. Таким образом, база данных знает, что не может быть соответствующей строки, прежде чем пытаться подключиться к JOIN. – Thilo

ответ

1

Это решение, использующее несколько LEFT JOINs, с демоверсией, используя предоставленные вами данные.

Окончательный запрос:

SELECT 
    s.title, 
    COALESCE(i1.path, i2.path) 
FROM songs s 
LEFT JOIN albums a ON s.album_id = a.id 
LEFT JOIN images i1 ON s.image_id = i1.id 
LEFT JOIN images i2 ON a.image_id = i2.id 
ORDER BY s.id; 

Ниже приведен полный демо.

SQL:

-- Data for demo 
create table albums(id int, title char(100), image_id int); 
insert into albums values 
(5 , 'First Album' ,  1), 
(6 , 'Another Album' ,  2); 

create table songs(id int, album_id int, title char(100), image_id int); 
insert into songs values 
(32 ,  5  , 'My Song' ,  3), 
(33 ,  5  , 'Another One' ,  4), 
(34 ,  5  , 'First Song' ,  0), 
(35 ,  6  , 'My Song #2' ,  0), 
(36 ,  6  , 'Fancy Title' ,  0), 
(37 ,  6  , 'My Love Song' ,  5); 

create table images(id int, path char(200)); 
insert into images values 
(1 , 'path/to/image1.jpg'), 
(2 , 'path/to/image2.jpg'), 
(3 , 'path/to/image3.jpg'), 
(4 , 'path/to/image4.jpg'), 
(5 , 'path/to/image5.jpg'); 

SELECT * FROM albums; 
SELECT * FROM songs; 
SELECT * FROM images; 

-- SQL needed 
SELECT 
    s.title, 
    COALESCE(i1.path, i2.path) 
FROM songs s 
LEFT JOIN albums a ON s.album_id = a.id 
LEFT JOIN images i1 ON s.image_id = i1.id 
LEFT JOIN images i2 ON a.image_id = i2.id 
ORDER BY s.id; 

Выход:

mysql> SELECT 
    -> s.title, 
    -> COALESCE(i1.path, i2.path) 
    -> FROM songs s 
    -> LEFT JOIN albums a ON s.album_id = a.id 
    -> LEFT JOIN images i1 ON s.image_id = i1.id 
    -> LEFT JOIN images i2 ON a.image_id = i2.id 
    -> ORDER BY s.id; 
+--------------+----------------------------+ 
| title  | COALESCE(i1.path, i2.path) | 
+--------------+----------------------------+ 
| My Song  | path/to/image3.jpg   | 
| Another One | path/to/image4.jpg   | 
| First Song | path/to/image1.jpg   | 
| My Song #2 | path/to/image2.jpg   | 
| Fancy Title | path/to/image2.jpg   | 
| My Love Song | path/to/image5.jpg   | 
+--------------+----------------------------+ 
6 rows in set (0.00 sec) 
3

Что-то, как это должно работать:

SELECT s.title, COALESCE(si.path, ai.path) 
FROM albums AS a 
INNER JOIN songs s ON a.id = s.album_id 
LEFT JOIN images ai ON i.id = a.image_id 
LEFT JOIN images si ON i.id = s.image_id 

Обратите внимание, что вы должны присоединиться к images таблицу в albums таблице и к songs таблице. ai и si служат в качестве отдельного пространства имен для этих объединений, так что COALESCE знает, как найти варианты на выбор.

(Обратите внимание, что INNER JOIN спорно в зависимости от того, как вы ожидаете ваши данные, чтобы посмотреть.)

+0

Лучше наденьте песни сверху. В противном случае он не будет воспроизводить песни без альбома. – Thilo

+0

@Thilo Хороший улов.Крепление! –

+0

Недостаточно COALESCE, поскольку у него есть 0, а не NULL для отсутствующих изображений. Но настройка, чтобы справиться с этим, не является серьезной. – mdahlman

1

Вы также можете использовать UNION таким образом:

SELECT songs.title, images.path 
FROM songs 
LEFT JOIN images ON (images.id = songs.image_id) 
WHERE songs.image_id != 0 
UNION 
SELECT songs.title, images.path 
FROM songs 
LEFT JOIN albums ON (songs.album_id = albums.id) 
LEFT JOIN images ON (images.id = albums.image_id) 
WHERE albums.image_id != 0 AND songs.image_id = 0 

В основном вы сначала выбрать все песни с изображение, затем добавьте все песни с изображением альбома, если сама песня не имеет его.