109

Does anyone an idea how to rewrite following SQL query to generate results, that would contains only one occurrence of name? (results grouped by user).

The query

SELECT array_to_string(array_agg(CONCAT(u.firstname, ' ', u.lastname)), ', ')
FROM log_has_item logitem
  INNER JOIN log log ON log.id = logitem.log_id
  INNER JOIN worker u ON log.worker_id = u.id
WHERE logitem.company_id = 1

Executable query is avaiable on sqlfiddle.com. Click on Run SQL button and you will result, which contains Frantisek Smith twice

8
  • 9
    array_agg(distinct concat(...))) Commented Oct 14, 2014 at 14:49
  • In postgre 9.0+ there is string_agg(text,text) function. It may be easier to write string_agg(CONCAT(...),', ') Commented Oct 14, 2014 at 15:30
  • @a_horse_with_no_name distinct works fine, but scrambles the order. Any way to preserve it? Commented Mar 3, 2016 at 13:57
  • @Rodrigo: use an order by inside string_agg() Commented Mar 3, 2016 at 13:58
  • @a_horse_with_no_name I tried string_agg(distinct nome order by l.id,', ') and string_agg(distinct nome order by nome,', '), but both give "function string_agg(character varying) does not exist". I'll ask a question with the full sql to show you. Commented Mar 3, 2016 at 14:00

2 Answers 2

188

You can use the distinct keyword inside array_agg:

SELECT ARRAY_TO_STRING(ARRAY_AGG(DISTINCT CONCAT(u.firstname, ' ', u.lastname)), ', ')
FROM log_has_item logitem
  INNER JOIN log log ON log.id = logitem.log_id
  INNER JOIN worker u ON log.worker_id = u.id
WHERE logitem.company_id = 1

SQLFiddle with this example

Sign up to request clarification or add additional context in comments.

4 Comments

Any way to preserve the order using distinct?
ERROR: DISTINCT is not implemented for window functions SQL State :0A000 (PostgreSQL 9.5.5)
Saved me from having to write my own aggregate function!
Wouldn't STRING_AGG be better? See my answer.
6

No need to go all round the houses with ARRAY_TO_STRING(ARRAY_AGG( when a simple STRING_AGG will do as follows (code available on the fiddle here):

--
-- Simplified
--

SELECT
  DISTINCT
  STRING_AGG
  (
    DISTINCT CONCAT(w.firstname, ' ', w.lastname), ', '
  ) AS "The workers"
FROM log_item li
INNER JOIN log l ON li.log_id = l.id 
INNER JOIN worker w ON l.worker_id = w.id
WHERE li.company_id = 1;

Result:

                The workers
Frantisek Smith, Peter Duff

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.