2017-08-30 1 views
2

Ich benutze Postgres 9.6. Meine Datenbank enthält Präsentationen, die zu Benutzern gehören. Jede Präsentation hat viele Folien. Jede Folie kann optional ein Hintergrundbild haben.Postgres: JOIN mit dem ersten Nicht-Null-Wert, der übereinstimmt?

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 

Ich möchte die Liste der Präsentationen für einen bestimmten Benutzer abzurufen, und zusammen mit dem Namen und der ID jeder Präsentation, würde ich gerne die ID des Hintergrundbildes von der ersten Folie erhalten, die eine hat Hintergrundbild (oder null, wenn keine seiner Folien ein Hintergrundbild hat). So kann ich neben jeder Präsentation ein Thumbnail präsentieren.

Zur Zeit habe ich eine Abfrage das Hintergrundbild ID der ersten Folie in der Präsentation erhält nur:

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; 

Aber ich mag, dies ändern, um den ersten Nicht-Null-Hintergrundbild ID zu erhalten jede Präsentation. Nicht sicher, wie man das macht!

Ich frage mich, ob Postgres first_value mir irgendwie helfen kann?

Antwort

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 
0

Es sieht wie Sie nur zwei Spalten benötigen die Informationen, die Sie fehlen zu bekommen.

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; 

Dies gibt Ihnen eine Zeile pro Präsentation.

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; 

sollten Sie umfassen CREATE TABLE und INSERT-Anweisungen in Ihrer Frage.

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); 
Verwandte Themen