Упорядочить по объединенному полю с отношением «многие ко многим» - PullRequest
0 голосов
/ 09 апреля 2020

В базе данных PostgreSQL есть две сущности с отношением "многие ко многим": songs имеют "многие ко многим" artists. artists_songs таблица используется для отношения. Я хочу выбрать песни и отсортировать их по первому исполнителю (отсортировано по алфавиту). В настоящее время PG не позволяет мне делать это без указания всех полей в группе. Можно ли выбирать и сортировать песни с группировкой только по songs.id?

Вот мой SQL запрос:

select ss.*
  from (
    select songs.*, min(artists.name) as artist_name
    from songs
      left join artists_songs on artists_songs.song_id = songs.id
      left join artists on artists.id = artists_songs.artist_id
      group by songs.id, artists.name
    ) ss
    group by ss.id
    order by ss.artist_name
    ;

Ответы [ 3 ]

1 голос
/ 09 апреля 2020

Это выглядит как хорошее место для бокового соединения:

select s.*, a.name
from songs s
cross join lateral (
    select a.name
    from artists_songs ars
    inner join artists a on a.id = ars.artist_id
    where ars.song_id = s.id
    order by a.name
    limit 1
) a
order by a.name
1 голос
/ 09 апреля 2020

Использование distinct on:

select distinct on (s.id) s.*, sa.name as artist_name
from songs s left join
     artists_songs ars
     on ars.song_id = s.id left join
     artists a
     on a.id = ars.artist_id    
order by s.id, sa.name;

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

select s.*
from (select distinct on (s.id) s.*, sa.name as artist_name
      from songs s left join
           artists_songs ars
           on ars.song_id = s.id left join
           artists a
           on a.id = ars.artist_id    
      order by s.id, sa.name
     ) s
order by artist_name
0 голосов
/ 09 апреля 2020

Лучшее решение, которое я когда-либо придумал, - это использовать оконную функцию, как @ gordon-linoff заявил изначально:

select s.id, min(a.name) over (partition by s.id) as artist_name
from songs s left join
    artists_songs ars
    on ars.song_id = s.id left join
    artists a
    on a.id = ars.artist_id
order by artist_name;
...