Lists: | pgsql-sql |
---|
From: | "Philippe Lang" <philippe(dot)lang(at)attiksystem(dot)ch> |
---|---|
To: | <pgsql-sql(at)postgresql(dot)org> |
Subject: | Concatenation through SQL |
Date: | 2007-12-21 10:33:40 |
Message-ID: | 6C0CF58A187DA5479245E0830AF84F42337F97@poweredge.attiksystem.ch |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
Hi,
Here is small reduced test database:
------------------------------
CREATE TABLE appointments
(
id integer,
name varchar(32),
CONSTRAINT appointments_pkey PRIMARY KEY (id)
);
CREATE TABLE employees
(
id integer,
appointment_id integer,
name varchar(32),
CONSTRAINT employees_pkey PRIMARY KEY (id),
CONSTRAINT appointments_employees_fkey FOREIGN KEY (appointment_id)
REFERENCES appointments (id)
);
INSERT INTO appointments VALUES (1, 'app1');
INSERT INTO employees VALUES (1, 1, 'emp1');
INSERT INTO employees VALUES (2, 1, 'emp2');
INSERT INTO employees VALUES (3, 1, 'emp3');
INSERT INTO appointments VALUES (2, 'app2');
INSERT INTO employees VALUES (4, 2, 'emp1');
INSERT INTO employees VALUES (5, 2, 'emp4');
------------------------------
I'm trying to write an SQL query that would return this:
---------------------------------------------------
appointment count_employees employees
---------------------------------------------------
app1 3 emp1, emp2, emp3
app2 2 emp1, emp4,
---------------------------------------------------
First part is easy to write:
------------------------------
SELECT
appointments.name AS appointment,
(SELECT COUNT(*) FROM employees AS e where e.appointment_id =
appointments.id) AS num_employees
FROM appointments
------------------------------
... But concatenating employees name is harder, at least for me...
I'm convinced this can be done with Set Returning Functions and a bit of
plpgsql, but I was wondering if it would possible to write some kind of
extension to Postgresql (operator?) that would allow this kind of
syntax:
------------------------------
SELECT
appointments.name AS appointment,
(SELECT COUNT(*) FROM employees AS e where e.appointment_id =
appointments.id) AS num_employees
(SELECT CONCAT(name, ', ') FROM employees AS e where e.appointment_id =
appointments.id) AS employees
FROM appointments
------------------------------
... where CONCAT suggest we want to concatenate the variable inside,
with the separator ', ' inbetween.
Thanks for your tips!
Philippe Lang
From: | Andreas Kretschmer <akretschmer(at)spamfence(dot)net> |
---|---|
To: | pgsql-sql(at)postgresql(dot)org |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 10:58:13 |
Message-ID: | 20071221105813.GA18247@KanotixBox |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
Philippe Lang <philippe(dot)lang(at)attiksystem(dot)ch> schrieb:
2 ways:
* You can use something like this:
test=*# select * from a;
id | val
----+-----
1 | foo
2 | bar
(2 rows)
test=*# select array_to_string(array(select val from a), ', ');
array_to_string
-----------------
foo, bar
(1 row)
* comma-aggregate, see
http://www.zigo.dhs.org/postgresql/#comma_aggregate
Andreas
--
Really, I'm not out to destroy Microsoft. That will just be a completely
unintentional side effect. (Linus Torvalds)
"If I was god, I would recompile penguin with --enable-fly." (unknow)
Kaufbach, Saxony, Germany, Europe. N 51.05082°, E 13.56889°
From: | "Pavel Stehule" <pavel(dot)stehule(at)gmail(dot)com> |
---|---|
To: | "Philippe Lang" <philippe(dot)lang(at)attiksystem(dot)ch> |
Cc: | pgsql-sql(at)postgresql(dot)org |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 11:07:17 |
Message-ID: | 162867790712210307s2e0bf4c3y1f2911c238375f27@mail.gmail.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
Hello
postgres=# select name, count, employes from (select appointment_id,
count(*), (SELECT array_to_string(ARRAY(SELECT name from employees
where appointment_id = e.appointment_id),',')) as employes from
employees e group by appointment_id)s join appointments a on a.id =
s.appointment_id;
name | count | employes
------+-------+----------------
app2 | 2 | emp1,emp4
app1 | 3 | emp1,emp2,emp3
(2 rows)
regards
Pavel Stehule
for longer table is better define own aggregate function.
On 21/12/2007, Philippe Lang <philippe(dot)lang(at)attiksystem(dot)ch> wrote:
> Hi,
>
> Here is small reduced test database:
>
> ------------------------------
> CREATE TABLE appointments
> (
> id integer,
> name varchar(32),
> CONSTRAINT appointments_pkey PRIMARY KEY (id)
> );
>
> CREATE TABLE employees
> (
> id integer,
> appointment_id integer,
> name varchar(32),
> CONSTRAINT employees_pkey PRIMARY KEY (id),
> CONSTRAINT appointments_employees_fkey FOREIGN KEY (appointment_id)
> REFERENCES appointments (id)
> );
>
> INSERT INTO appointments VALUES (1, 'app1');
> INSERT INTO employees VALUES (1, 1, 'emp1');
> INSERT INTO employees VALUES (2, 1, 'emp2');
> INSERT INTO employees VALUES (3, 1, 'emp3');
>
> INSERT INTO appointments VALUES (2, 'app2');
> INSERT INTO employees VALUES (4, 2, 'emp1');
> INSERT INTO employees VALUES (5, 2, 'emp4');
> ------------------------------
>
>
> I'm trying to write an SQL query that would return this:
>
> ---------------------------------------------------
> appointment count_employees employees
> ---------------------------------------------------
> app1 3 emp1, emp2, emp3
> app2 2 emp1, emp4,
> ---------------------------------------------------
>
> First part is easy to write:
>
> ------------------------------
> SELECT
> appointments.name AS appointment,
> (SELECT COUNT(*) FROM employees AS e where e.appointment_id =
> appointments.id) AS num_employees
> FROM appointments
> ------------------------------
>
> ... But concatenating employees name is harder, at least for me...
>
> I'm convinced this can be done with Set Returning Functions and a bit of
> plpgsql, but I was wondering if it would possible to write some kind of
> extension to Postgresql (operator?) that would allow this kind of
> syntax:
>
> ------------------------------
> SELECT
> appointments.name AS appointment,
> (SELECT COUNT(*) FROM employees AS e where e.appointment_id =
> appointments.id) AS num_employees
> (SELECT CONCAT(name, ', ') FROM employees AS e where e.appointment_id =
> appointments.id) AS employees
> FROM appointments
> ------------------------------
>
> ... where CONCAT suggest we want to concatenate the variable inside,
> with the separator ', ' inbetween.
>
> Thanks for your tips!
>
>
> Philippe Lang
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 7: You can help support the PostgreSQL project by donating at
>
> http://www.postgresql.org/about/donate
>
From: | "Leif B(dot) Kristensen" <leif(at)solumslekt(dot)org> |
---|---|
To: | pgsql-sql(at)postgresql(dot)org |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 11:16:45 |
Message-ID: | 200712211216.45186.leif@solumslekt.org |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
On Friday 21. December 2007, Philippe Lang wrote:
>(SELECT CONCAT(name, ', ') FROM employees AS e where e.appointment_id
> = appointments.id) AS employees
>FROM appointments
>------------------------------
>
>... where CONCAT suggest we want to concatenate the variable inside,
>with the separator ', ' inbetween.
I've got a similar problem. My persons table has a number of fields for
different name parts: given, patronym, toponym, surname, occupation,
epithet. I've written a Plpgsql function that concatenates the full
name, but it's big and ugly. I'd like something more elegant, like the
Python or PHP join() function. I tried Andreas' suggestion like this:
pgslekt=> select array_to_string(array(select given, patronym, toponym
from persons where person_id=57), ' ');
ERROR: subquery must return only one column
Is there any way to accomplish this from Plpgsql?
--
Leif Biberg Kristensen | Registered Linux User #338009
http://solumslekt.org/ | Cruising with Gentoo/KDE
My Jazz Jukebox: http://www.last.fm/user/leifbk/
From: | imad <immaad(at)gmail(dot)com> |
---|---|
To: | "Leif B(dot) Kristensen" <leif(at)solumslekt(dot)org> |
Cc: | pgsql-sql(at)postgresql(dot)org |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 11:51:58 |
Message-ID: | 1f30b80c0712210351v383d9a8cxbd6d085d1646841d@mail.gmail.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
On Dec 21, 2007 4:16 PM, Leif B. Kristensen <leif(at)solumslekt(dot)org> wrote:
> On Friday 21. December 2007, Philippe Lang wrote:
>
> >(SELECT CONCAT(name, ', ') FROM employees AS e where e.appointment_id
> > = appointments.id) AS employees
> >FROM appointments
> >------------------------------
> >
> >... where CONCAT suggest we want to concatenate the variable inside,
> >with the separator ', ' inbetween.
>
> I've got a similar problem. My persons table has a number of fields for
> different name parts: given, patronym, toponym, surname, occupation,
> epithet. I've written a Plpgsql function that concatenates the full
> name, but it's big and ugly. I'd like something more elegant, like the
> Python or PHP join() function. I tried Andreas' suggestion like this:
>
> pgslekt=> select array_to_string(array(select given, patronym, toponym
> from persons where person_id=57), ' ');
> ERROR: subquery must return only one column
Try concatenating your columns using the '||' operator or 'concat' function
and project only one column from the subquery. You won't need to convert it
to an array and back to string.
--Imad
Database Expert
From: | Niklas Johansson <spot(at)tele2(dot)se> |
---|---|
To: | Leif B(dot) Kristensen <leif(at)solumslekt(dot)org> |
Cc: | pgsql-sql(at)postgresql(dot)org |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 12:07:00 |
Message-ID: | 520638AC-01E3-48C6-A480-DEB5E56139E5@tele2.se |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
On 21 dec 2007, at 12.16, Leif B. Kristensen wrote:
> I've got a similar problem. My persons table has a number of fields
> for
> different name parts: given, patronym, toponym, surname, occupation,
> epithet.
> I'd like something more elegant, like the
> Python or PHP join() function. I tried Andreas' suggestion like this:
>
> pgslekt=> select array_to_string(array(select given, patronym, toponym
> from persons where person_id=57), ' ');
> ERROR: subquery must return only one column
Your case is not the same as Philippe's, since you have the values to
be concatenated in columns, whereas he had them in rows.
However, something like this would probably achieve what you're
looking for:
select array_to_string(array[given, patronym, toponym], ' ') from
persons where person_id=57;
Notice the use of the array[] constructor, instead of the array()
constructor, which must be fed a subquery which returns only one column.
From: | "Leif B(dot) Kristensen" <leif(at)solumslekt(dot)org> |
---|---|
To: | pgsql-sql(at)postgresql(dot)org |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 12:31:14 |
Message-ID: | 200712211331.14239.leif@solumslekt.org |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
On Friday 21. December 2007, Niklas Johansson wrote:
>select array_to_string(array[given, patronym, toponym], ' ') from
>persons where person_id=57;
>
>Notice the use of the array[] constructor, instead of the array()
>constructor, which must be fed a subquery which returns only one
> column.
Aah, great!
pgslekt=> select array_to_string(array[given, patronym, toponym], ' ')
from persons where person_id=57;
array_to_string
--------------------------
Abraham Jonsen Bjørntvet
(1 row)
Tackar och bockar!
--
Leif Biberg Kristensen | Registered Linux User #338009
http://solumslekt.org/ | Cruising with Gentoo/KDE
My Jazz Jukebox: http://www.last.fm/user/leifbk/
From: | "Philippe Lang" <philippe(dot)lang(at)attiksystem(dot)ch> |
---|---|
To: | <pgsql-sql(at)postgresql(dot)org> |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 13:48:55 |
Message-ID: | 6C0CF58A187DA5479245E0830AF84F4218CFBE@poweredge.attiksystem.ch |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
pgsql-sql-owner(at)postgresql(dot)org wrote:
> Philippe Lang <philippe(dot)lang(at)attiksystem(dot)ch> schrieb:
>
> 2 ways:
>
> * You can use something like this:
>
> test=*# select * from a;
> id | val
> ----+-----
> 1 | foo
> 2 | bar
> (2 rows)
>
> test=*# select array_to_string(array(select val from a), ', ');
> array_to_string -----------------
> foo, bar
> (1 row)
>
>
> * comma-aggregate, see
> http://www.zigo.dhs.org/postgresql/#comma_aggregate
Hi,
Thanks to all who responded, in particular Andreas. I'm always amazed by
the quality of both the Postgresql database and the support in its
newsgroups.
The "comma-aggregate" worked just fine for me. Here is the final
example, for those willing to test it. This will be more than useful!
---------------------------------------
CREATE TABLE appointments
(
id integer,
name varchar(32),
CONSTRAINT appointments_pkey PRIMARY KEY (id)
);
CREATE TABLE employees
(
id integer,
appointment_id integer,
name varchar(32),
CONSTRAINT employees_pkey PRIMARY KEY (id),
CONSTRAINT appointments_employees_fkey FOREIGN KEY (appointment_id)
REFERENCES appointments (id)
);
INSERT INTO appointments VALUES (1, 'app1');
INSERT INTO employees VALUES (1, 1, 'emp1');
INSERT INTO employees VALUES (2, 1, 'emp2');
INSERT INTO employees VALUES (3, 1, 'emp3');
INSERT INTO appointments VALUES (2, 'app2');
INSERT INTO employees VALUES (4, 2, 'emp1');
INSERT INTO employees VALUES (5, 2, 'emp4');
CREATE AGGREGATE array_accum (anyelement)
(
sfunc = array_append,
stype = anyarray,
initcond = '{}'
);
SELECT
appointments.name AS appointment,
(SELECT COUNT(*) FROM employees AS e where e.appointment_id =
appointments.id) AS num_employees,
(SELECT array_to_string(array_accum(name),', ') FROM employees AS e
WHERE e.appointment_id = appointments.id) AS employees
FROM appointments
---------------------------------------
Result:
---------------------------------------------------
appointment count_employees employees
---------------------------------------------------
app1 3 emp1, emp2, emp3
app2 2 emp1, emp4,
---------------------------------------------------
Merry christmas to all.
Philippe
From: | "Pavel Stehule" <pavel(dot)stehule(at)gmail(dot)com> |
---|---|
To: | "Philippe Lang" <philippe(dot)lang(at)attiksystem(dot)ch> |
Cc: | pgsql-sql(at)postgresql(dot)org |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 14:24:46 |
Message-ID: | 162867790712210624y1e3454ffw8d4bffff69819335@mail.gmail.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
On 21/12/2007, Philippe Lang <philippe(dot)lang(at)attiksystem(dot)ch> wrote:
> pgsql-sql-owner(at)postgresql(dot)org wrote:
> > Philippe Lang <philippe(dot)lang(at)attiksystem(dot)ch> schrieb:
> >
> > 2 ways:
> >
> > * You can use something like this:
> >
> > test=*# select * from a;
> > id | val
> > ----+-----
> > 1 | foo
> > 2 | bar
> > (2 rows)
> >
> > test=*# select array_to_string(array(select val from a), ', ');
> > array_to_string -----------------
> > foo, bar
> > (1 row)
> >
> >
> > * comma-aggregate, see
> > http://www.zigo.dhs.org/postgresql/#comma_aggregate
>
> Hi,
>
> Thanks to all who responded, in particular Andreas. I'm always amazed by
> the quality of both the Postgresql database and the support in its
> newsgroups.
>
> The "comma-aggregate" worked just fine for me. Here is the final
> example, for those willing to test it. This will be more than useful!
>
> ---------------------------------------
> CREATE TABLE appointments
> (
> id integer,
> name varchar(32),
> CONSTRAINT appointments_pkey PRIMARY KEY (id)
> );
>
> CREATE TABLE employees
> (
> id integer,
> appointment_id integer,
> name varchar(32),
> CONSTRAINT employees_pkey PRIMARY KEY (id),
> CONSTRAINT appointments_employees_fkey FOREIGN KEY (appointment_id)
> REFERENCES appointments (id)
> );
>
> INSERT INTO appointments VALUES (1, 'app1');
> INSERT INTO employees VALUES (1, 1, 'emp1');
> INSERT INTO employees VALUES (2, 1, 'emp2');
> INSERT INTO employees VALUES (3, 1, 'emp3');
>
> INSERT INTO appointments VALUES (2, 'app2');
> INSERT INTO employees VALUES (4, 2, 'emp1');
> INSERT INTO employees VALUES (5, 2, 'emp4');
>
> CREATE AGGREGATE array_accum (anyelement)
> (
> sfunc = array_append,
> stype = anyarray,
> initcond = '{}'
> );
>
> SELECT
> appointments.name AS appointment,
> (SELECT COUNT(*) FROM employees AS e where e.appointment_id =
> appointments.id) AS num_employees,
> (SELECT array_to_string(array_accum(name),', ') FROM employees AS e
> WHERE e.appointment_id = appointments.id) AS employees
> FROM appointments
> ---------------------------------------
>
hello,
one note: you can merge your two subselect into one. It's unimportant
on 100 rows, but it's can be important on thousands rows.
nice a day
Pavel
>
> Result:
>
> ---------------------------------------------------
> appointment count_employees employees
> ---------------------------------------------------
> app1 3 emp1, emp2, emp3
> app2 2 emp1, emp4,
> ---------------------------------------------------
>
>
> Merry christmas to all.
>
> Philippe
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: In versions below 8.0, the planner will ignore your desire to
> choose an index scan if your joining column's datatypes do not
> match
>
From: | "Philippe Lang" <philippe(dot)lang(at)attiksystem(dot)ch> |
---|---|
To: | <pgsql-sql(at)postgresql(dot)org> |
Subject: | Re: Concatenation through SQL |
Date: | 2007-12-21 16:01:28 |
Message-ID: | 6C0CF58A187DA5479245E0830AF84F4218CFC1@poweredge.attiksystem.ch |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-sql |
Pavel Stehule wrote:
>> SELECT
>> appointments.name AS appointment,
>> (SELECT COUNT(*) FROM employees AS e where e.appointment_id =
>> appointments.id) AS num_employees,
>> (SELECT array_to_string(array_accum(name),', ') FROM employees AS e
>> WHERE e.appointment_id = appointments.id) AS employees FROM
>> appointments ---------------------------------------
>>
>
> hello,
>
> one note: you can merge your two subselect into one. It's unimportant
> on 100 rows, but it's can be important on thousands rows.
>
> nice a day
> Pavel
Hi Pavel,
Since subselects must return one single column, is that what you are
talking about? I have just modified the code you have posted before.
---------------------------
SELECT
name AS appointment,
num_employees,
employees
FROM
(
SELECT
appointment_id,
COUNT(*) AS num_employees,
(SELECT array_to_string(array_accum(name),', ') FROM employees WHERE
e.appointment_id = appointment_id) AS employees
FROM employees e
GROUP BY appointment_id
)s
JOIN appointments a on a.id = s.appointment_id;
---------------------------
Philippe