Pregunta

ID | user_id | name      | active
1  | 1       | Profile 1 | f
2  | 1       | Profile 2 | t
3  | 2       | Profile 3 | f
4  | 2       | Profile 4 | f
5  | 3       | Profile 5 | f

I'm using PostgreSQL. In my application,users can create multiple profiles and I want to select last distinct inactive profiles created by each user. Also, if there is an active profile belongs to that user, it should not select any profile from that user -- that was the hard part for me.

What kind of SQL statement I should use in order to get the following results?

4  | 2       | Profile 4 | f
5  | 3       | Profile 5 | f
¿Fue útil?

Solución

I would combine DISTINCT ON with NOT EXISTS. Assuming a proper boolean type for active:

SELECT DISTINCT ON (user_id)
       id, user_id, name, active
FROM   profiles p
WHERE  NOT EXISTS (
   SELECT 1 FROM profiles
   WHERE  user_id = p.user_id
   AND    active               -- exclude users with any active profiles
   )
ORDER  BY user_id, id DESC;

Probably fastest and cleanest.

Otros consejos

SQL Fiddle

select distinct on (user_id)
    id, user_id, name, active
from
    t
    inner join
    (
        select user_id
        from t
        group by user_id
        having not bool_or(active)
    ) s using(user_id)
order by user_id, id desc

The distinct on syntax works very well for this:

select distinct on (user_id) id, user_id, name, active
from t
where active = 'f'
order by user_id, id desc;

EDIT:

To avoid an active profile, it probably easier to go to analytic functions:

select id, user_id, name, active
from (select t.*,
             row_number() over (partition by user_id, active order by id desc) as seqnum,
             max(case when active = 'f' then 0 else 1 end) as numActives
      from t
     ) t
where numActives = 0 and seqnum = 1;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top