2

With the following query

SELECT
  users.id,
  users.username,
  users.email,
  groups.permission
FROM users
INNER JOIN memberships ON users.id = memberships.user_id
INNER JOIN groups ON memberships.group_id = groups.id
INNER JOIN groupings ON groups.id = groupings.group_id
WHERE groupings.repo_id = 1
GROUP BY users.id, groups.permission
ORDER BY users.id

I get the following rows:

----+---------------------------+-----------------------------------------+------------
 id |         username          |                  email                  | permission 
----+---------------------------+-----------------------------------------+------------
  2 | viva_leuschke0            | viva_leuschke0@ritchiealtenwerth.org    | 1
  2 | viva_leuschke0            | viva_leuschke0@ritchiealtenwerth.org    | 2
  3 | loyce_herman1             | herman1.loyce@bednar.com                | 1
  3 | loyce_herman1             | herman1.loyce@bednar.com                | 3
  4 | verona_vandervort2        | verona.vandervort2@mante.biz            | 1
  4 | verona_vandervort2        | verona.vandervort2@mante.biz            | 2
  4 | verona_vandervort2        | verona.vandervort2@mante.biz            | 3
  5 | bruen3_ms_hans            | ms.bruen3.hans@bechtelar.net            | 1
  5 | bruen3_ms_hans            | ms.bruen3.hans@bechtelar.net            | 2
  5 | bruen3_ms_hans            | ms.bruen3.hans@bechtelar.net            | 3
----+---------------------------+-----------------------------------------+------------

The question is: how can I tweak this query to return unique rows, filtering by the highest permission value? Something like:

----+---------------------------+-----------------------------------------+------------
 id |         username          |                  email                  | permission 
----+---------------------------+-----------------------------------------+------------
  2 | viva_leuschke0            | viva_leuschke0@ritchiealtenwerth.org    | 2
  3 | loyce_herman1             | herman1.loyce@bednar.com                | 3
  4 | verona_vandervort2        | verona.vandervort2@mante.biz            | 3
  5 | bruen3_ms_hans            | ms.bruen3.hans@bechtelar.net            | 3
----+---------------------------+-----------------------------------------+------------

I'm using PostgreSQL 9.1.

UPDATE: By using the DISTINCT ON clause I was able to get what I wanted.

SELECT DISTINCT ON(users.id)
  users.id,
  users.username,
  users.email,
  groups.permission
FROM users
INNER JOIN memberships ON users.id = memberships.user_id
INNER JOIN groups ON memberships.group_id = groups.id
INNER JOIN groupings ON groups.id = groupings.group_id
WHERE groupings.repo_id = 1
GROUP BY users.id, groups.permission
ORDER BY 
  users.id ASC, 
  groups.permission DESC

Is this the best way of doing it?

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
Nando Vieira
  • 964
  • 10
  • 17

1 Answers1

1

On closer inspection, your query can (and should) be improved:


SELECT DISTINCT ON (u.id)
      ,u.id
      ,u.username
      ,u.email
      ,g.permission
FROM   users       u
JOIN   memberships m  ON m.user_id = u.id
JOIN   groups      g  ON g.id = m.group_id
JOIN   groupings   gi ON gi.group_id = g.id 
WHERE  gi.repo_id = 1
GROUP  BY u.id, g.permission
ORDER  BY u.id, g.permission DESC

The GROUP BY is of no use. DISTINCT ON alone gives you a unique users.id. Remove the GROUP BY, you'll get the same result, just faster.

You may want to add more columns to ORDER BY to decide which row to pick where more than one per id share the highest permission. The way you have it, you get an arbitrary pick for this case (provided it can occur).

My reference answer for this query technique has more explanation, a benchmark and links.

Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228