Postgres:JOIN与第一个匹配的非null值?

时间:2017-08-30 17:27:18

标签: sql postgresql

我正在使用Postgres 9.6。我的数据库包含属于用户的演示文稿。每个演示文稿都有很多幻灯每个幻灯片可以可选地具有背景图像。

Table "public.presentation"
id             │ integer
user_id        │ integer

Table "public.slide"
id               | integer
presentation_id  | integer (foreign key)
index            | integer

Table "public.background"
slide_id .     | integer (foreign key)
image_id       │ integer

我想检索特定用户的演示文稿列表,以及每个演示文稿的名称和ID,我想获得具有背景图像的第一张幻灯片的背景图像的ID(或者如果它的幻灯片都没有背景图像,则返回null)。这样我就可以在每个演示文稿旁边显示缩略图。

目前我有一个查询只能获取演示文稿中第一张幻灯片的背景图片ID:

SELECT presentation.*, background.image_id 
FROM presentation 
JOIN -- get the first slide in each presentation
  (SELECT presentation_id FROM slide WHERE index=0) 
  ON slide.presentation_id=presentation.id
LEFT OUTER JOIN -- join this with background (even if null)
  background ON background.slide_id=slide.id
WHERE presentation.user_id=100
ORDER BY presentation.id;

但我想更改此设置以获取每个演示文稿的第一个非空背景图像ID。不知道怎么做!

我想知道Postgres的first_value能否以某种方式帮助我?

2 个答案:

答案 0 :(得分:1)

select *
from
    presentation
    left join (
        select
            b.image_id, s.presentation_id as id,
            row_number() over (
                partition by s.presentation_id
                order by s.index
            ) as rn
        from
            slide s
            inner join
            background b on b.slide_id = s.id
    ) b using (id)
where rn = 1 or rn is null

答案 1 :(得分:0)

看起来就像你只需要两列就能获得你所遗漏的信息。

select slide.presentation_id, min(background.image_id) as background_image_id
from slide
left join background
    on slide.id = background.slide_id
group by slide.presentation_id
order by slide.presentation_id, background_image_id;

这为每个演示文稿提供了一行。

with first_background_image as (
    select slide.presentation_id, min(background.image_id) as background_image_id
    from slide
    left join background
        on slide.id = background.slide_id
    group by slide.presentation_id
), first_slide as (
    select presentation_id, min(index) as first_slide_id
    from slide
    group by presentation_id
)
select fs.presentation_id, fs.first_slide_id, fbi.background_image_id
from first_slide fs
left join first_background_image fbi
    on fbi.presentation_id = fs.presentation_id
order by presentation_id;

您应该在问题中包含CREATE TABLE和INSERT语句。

create table presentation (
    id integer primary key,
    user_id integer not null
);

create table slide (
    id integer primary key,
    presentation_id integer not null 
        references presentation (id),
    index integer not null,
    unique (presentation_id, index)
);

create table background (
    -- Assumes one background per slide.
    slide_id integer primary key
        references slide (id),
    image_id integer not null
        -- references something?
);

insert into presentation values (1, 1), (2, 1), (3, 2);
insert into slide values (1, 1, 1), (2, 1, 2), (3, 1, 3), (4, 2, 1), (5, 2, 2), (6, 3, 1);
insert into background values (1, 3), (2, 7), (5, 18);