Home > Blockchain >  filter query and keep full aggregate data
filter query and keep full aggregate data

Time:07-07

I have this database:

create table if not exists blog
(
    id                          serial        primary key,
    domain                      text
);

create table if not exists blog_category
(
    id          serial        primary key,
    name        text
);

create table if not exists blog_to_blog_category
(
    id               serial        primary key,
    blog_id          integer not null
        constraint "FK_blog_to_blog_category_blog_BlogId"
            references blog,
    blog_category_id integer not null
        constraint "FK_blog_to_blog_category_blog_category_BlogCategoryId"
            references blog_category
);


INSERT INTO blog VALUES
    (1, 'one.com'),
    (2, 'two.com'),
    (3, 'three.com');

INSERT INTO blog_category VALUES
    (1, 'business'),
    (2, 'marketing'),
    (3, 'misc');

INSERT INTO blog_to_blog_category VALUES
    (1, 1, 1),
    (2, 1, 2),
    (3, 1, 3),
    (4, 2, 1),
    (5, 2, 3);

I can get the data in format that I want by making a query like this:

select b.id, b.domain, coalesce( array_agg(bc.name) 
    filter (where bc.id is not null), '{}' ) as cats
from blog b
left join blog_to_blog_category bt on bt.blog_id = b.id
left join blog_category bc on bc.id = bt.blog_category_id
group by b.id

enter image description here

However, I can't work out how to filter it and also keep each record showing all categories it is in. for example:

select b.id, b.domain, coalesce( array_agg(bc.name) 
    filter (where bc.id is not null), '{}' ) as cats
from blog b
left join blog_to_blog_category bt on bt.blog_id = b.id
left join blog_category bc on bc.id = bt.blog_category_id

where bc.name = 'marketing'
group by b.id

enter image description here

It filters the blog correctly but now I can't aggregate all categories into a field. It only shows 1 category the blog is in.

What is the simplest way to be able to filter blogs and get a list of all of their categories?

CodePudding user response:

Try to select blog_id from blog_to_blog_category by blog_category.name

select b.id, b.domain, coalesce( array_agg(bc.name) 
    filter (where bc.id is not null), '{}' ) as cats
from blog b
left join blog_to_blog_category bt on bt.blog_id = b.id
left join blog_category bc on bc.id = bt.blog_category_id

where bt.blog_id = (
    select bt.blog_id from blog_to_blog_category bt
    left join blog_category bc on bc.id = bt.blog_category_id
    where bc.name = 'marketing'
)
group by b.id;
  • Related