Thread: query from two tables & concat the result
$ psql -V psql (PostgreSQL) 9.4.5 I am quite a newbie in psql. I am setting an email server and need to create then query psql tables to get some information: mainly email address and mail directory. For now I have created two tables this way. Both tables are in same database and schema. I only insert one row in each. 1- the first one is just a list of all my domains. ----------------------------------------- CREATE TABLE email.domain ( id SERIAL, domain TEXT NOT NULL, PRIMARY KEY (id) ); --------------------------------- 2- second is a list of users -------------------------------------------------- CREATE TABLE email.mailusers ( id SERIAL PRIMARY KEY, domain_id INTEGER DEFAULT 1, <<-- This ref to email.domain id=1 password TEXT NOT NULL, username TEXT UNIQUE NOT NULL, created TIMESTAMP WITH TIME ZONE DEFAULT now(); ------------------------------------ 3- Then I added a constraint: --------------------------------- ALTER TABLE email.mailusers ADD CONSTRAINT mailuser_domain_id_fkey FOREIGN KEY (domain_id) REFERENCES email.domain(id) ON UPDATE CASCADE ON DELETE RESTRICT; ------------------------------------- Then I need to retrieve from psql to postfix this parameter value: - email adress . The email address is obviously something like a a concat (username,'@',domain). My first idea is to create a view (or materialized view ?) following the principle described here[1] create view postfix_virtual as select userid, userid as address from users union all select userid, address from virtual; , but I am a little lost when it comes to the UNION stuff (shall I use it ?). Second possibility would be to create a modified query similar to this[2]: query = SELECT concat(username,'@',domain) as email FROM users WHERE username='%s' From now, I am able to create a view like this: --------------------------------------------- CREATE VIEW email_address AS SELECT * FROM (SELECT username FROM email.mailusers WHERE id=2)a, (SELECT domain FROM email.domain WHERE id=1)b; --------------------------------- I get a table: username | domain ---------------------+-------------------- myuser.name | mydomain.com That's fine, but it is far from being generic and satisfying. Thank you for help and advises. [1]http://wiki2.dovecot.org/HowTo/DovecotPostgresql/ [2]https://blog.za3k.com/installing-email-with-postfix-and-dovecot/ google.com/+arnaudgabourygabx
On Wed, Feb 3, 2016 at 1:18 PM, arnaud gaboury <arnaud.gaboury@gmail.com> wrote: > $ psql -V > psql (PostgreSQL) 9.4.5 > > I am quite a newbie in psql. I am setting an email server and need to > create then query psql tables to get some information: mainly email > address and mail directory. > > For now I have created two tables this way. Both tables are in same > database and schema. I only insert one row in each. > > 1- the first one is just a list of all my domains. > > ----------------------------------------- > CREATE TABLE email.domain ( > id SERIAL, > domain TEXT NOT NULL, > PRIMARY KEY (id) > ); > --------------------------------- > > 2- second is a list of users > > -------------------------------------------------- > CREATE TABLE email.mailusers ( > id SERIAL PRIMARY KEY, > domain_id INTEGER DEFAULT 1, <<-- This ref to email.domain id=1 > password TEXT NOT NULL, > username TEXT UNIQUE NOT NULL, > created TIMESTAMP WITH TIME ZONE DEFAULT now(); > ------------------------------------ > > 3- Then I added a constraint: > > --------------------------------- > ALTER TABLE email.mailusers > ADD CONSTRAINT mailuser_domain_id_fkey > FOREIGN KEY (domain_id) > REFERENCES email.domain(id) > ON UPDATE CASCADE > ON DELETE RESTRICT; > ------------------------------------- > > > Then I need to retrieve from psql to postfix this parameter value: > - email adress . > The email address is obviously something like a a concat (username,'@',domain). > > My first idea is to create a view (or materialized view ?) following > the principle described here[1] > > create view postfix_virtual as > select userid, userid as address from users > union all > select userid, address from virtual; > > , but I am a little lost when it comes to the UNION stuff (shall I use it ?). > > Second possibility would be to create a modified query similar to this[2]: > > query = SELECT concat(username,'@',domain) as email FROM users WHERE > username='%s' > > From now, I am able to create a view like this: > > --------------------------------------------- > CREATE VIEW email_address AS > SELECT * FROM > (SELECT username > FROM email.mailusers > WHERE id=2)a, > (SELECT domain > FROM email.domain > WHERE id=1)b; > --------------------------------- > I get a table: > username | domain > ---------------------+-------------------- > myuser.name | mydomain.com > > That's fine, but it is far from being generic and satisfying. > > Thank you for help and advises. > > [1]http://wiki2.dovecot.org/HowTo/DovecotPostgresql/ > [2]https://blog.za3k.com/installing-email-with-postfix-and-dovecot/ > EDIT: I deleted my first INSERT in table email.mailusers this way: DELETE * FROM email.mailusers , and now the id is set to 2. I would prefer having the id reset to 1. What is the correct way to get back id to 1 ? -- google.com/+arnaudgabourygabx
On 03/02/2016 12:18, arnaud gaboury wrote: > $ psql -V > psql (PostgreSQL) 9.4.5 > > I am quite a newbie in psql. I am setting an email server and need to > create then query psql tables to get some information: mainly email > address and mail directory. > > For now I have created two tables this way. Both tables are in same > database and schema. I only insert one row in each. > > 1- the first one is just a list of all my domains. > > ----------------------------------------- > CREATE TABLE email.domain ( > id SERIAL, > domain TEXT NOT NULL, > PRIMARY KEY (id) > ); > --------------------------------- > > 2- second is a list of users > > -------------------------------------------------- > CREATE TABLE email.mailusers ( > id SERIAL PRIMARY KEY, > domain_id INTEGER DEFAULT 1, <<-- This ref to email.domain id=1 > password TEXT NOT NULL, > username TEXT UNIQUE NOT NULL, > created TIMESTAMP WITH TIME ZONE DEFAULT now(); > ------------------------------------ > > 3- Then I added a constraint: > > --------------------------------- > ALTER TABLE email.mailusers > ADD CONSTRAINT mailuser_domain_id_fkey > FOREIGN KEY (domain_id) > REFERENCES email.domain(id) > ON UPDATE CASCADE > ON DELETE RESTRICT; > ------------------------------------- > > > Then I need to retrieve from psql to postfix this parameter value: > - email adress . > The email address is obviously something like a a concat (username,'@',domain). You can do a simple join between the tables (the string concatenation operator is ||): select u.username || '@' || d.domain as email_address from mailusers u inner join domain d on (u.domain_id = d.domain_id) where ..... Note that "domain" is a reserved work, so you'll probably have either to double-quote it or else rename that column to something else. Also, you really don't need so many id-type columns... given that the domain and username are presumably unique in their respective tables, having additional serial and domain_id columns seems like overkill. Why not ditch them and use the domain name and username as the primary keys? Ray. -- Raymond O'Donnell :: Galway :: Ireland rod@iol.ie
For resetting the id you may want to take a look at the sequence manipulation functions [1]
Regards,
Ricardo
[1]http://www.postgresql.org/docs/current/static/functions-sequence.html
On Wed, Feb 3, 2016, 06:26 arnaud gaboury <arnaud.gaboury@gmail.com> wrote:
On Wed, Feb 3, 2016 at 1:18 PM, arnaud gaboury <arnaud.gaboury@gmail.com> wrote:
> $ psql -V
> psql (PostgreSQL) 9.4.5
>
> I am quite a newbie in psql. I am setting an email server and need to
> create then query psql tables to get some information: mainly email
> address and mail directory.
>
> For now I have created two tables this way. Both tables are in same
> database and schema. I only insert one row in each.
>
> 1- the first one is just a list of all my domains.
>
> -----------------------------------------
> CREATE TABLE email.domain (
> id SERIAL,
> domain TEXT NOT NULL,
> PRIMARY KEY (id)
> );
> ---------------------------------
>
> 2- second is a list of users
>
> --------------------------------------------------
> CREATE TABLE email.mailusers (
> id SERIAL PRIMARY KEY,
> domain_id INTEGER DEFAULT 1, <<-- This ref to email.domain id=1
> password TEXT NOT NULL,
> username TEXT UNIQUE NOT NULL,
> created TIMESTAMP WITH TIME ZONE DEFAULT now();
> ------------------------------------
>
> 3- Then I added a constraint:
>
> ---------------------------------
> ALTER TABLE email.mailusers
> ADD CONSTRAINT mailuser_domain_id_fkey
> FOREIGN KEY (domain_id)
> REFERENCES email.domain(id)
> ON UPDATE CASCADE
> ON DELETE RESTRICT;
> -------------------------------------
>
>
> Then I need to retrieve from psql to postfix this parameter value:
> - email adress .
> The email address is obviously something like a a concat (username,'@',domain).
>
> My first idea is to create a view (or materialized view ?) following
> the principle described here[1]
>
> create view postfix_virtual as
> select userid, userid as address from users
> union all
> select userid, address from virtual;
>
> , but I am a little lost when it comes to the UNION stuff (shall I use it ?).
>
> Second possibility would be to create a modified query similar to this[2]:
>
> query = SELECT concat(username,'@',domain) as email FROM users WHERE
> username='%s'
>
> From now, I am able to create a view like this:
>
> ---------------------------------------------
> CREATE VIEW email_address AS
> SELECT * FROM
> (SELECT username
> FROM email.mailusers
> WHERE id=2)a,
> (SELECT domain
> FROM email.domain
> WHERE id=1)b;
> ---------------------------------
> I get a table:
> username | domain
> ---------------------+--------------------
> myuser.name | mydomain.com
>
> That's fine, but it is far from being generic and satisfying.
>
> Thank you for help and advises.
>
> [1]http://wiki2.dovecot.org/HowTo/DovecotPostgresql/
> [2]https://blog.za3k.com/installing-email-with-postfix-and-dovecot/
>
EDIT: I deleted my first INSERT in table email.mailusers this way:
DELETE * FROM email.mailusers
, and now the id is set to 2. I would prefer having the id reset to 1.
What is the correct way to get back id to 1 ?
--
google.com/+arnaudgabourygabx
--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general
On Wed, Feb 3, 2016 at 1:51 PM, Raymond O'Donnell <rod@iol.ie> wrote: > On 03/02/2016 12:18, arnaud gaboury wrote: >> $ psql -V >> psql (PostgreSQL) 9.4.5 >> >> I am quite a newbie in psql. I am setting an email server and need to >> create then query psql tables to get some information: mainly email >> address and mail directory. >> >> For now I have created two tables this way. Both tables are in same >> database and schema. I only insert one row in each. >> >> 1- the first one is just a list of all my domains. >> >> ----------------------------------------- >> CREATE TABLE email.domain ( >> id SERIAL, >> domain TEXT NOT NULL, >> PRIMARY KEY (id) >> ); >> --------------------------------- >> >> 2- second is a list of users >> >> -------------------------------------------------- >> CREATE TABLE email.mailusers ( >> id SERIAL PRIMARY KEY, >> domain_id INTEGER DEFAULT 1, <<-- This ref to email.domain id=1 >> password TEXT NOT NULL, >> username TEXT UNIQUE NOT NULL, >> created TIMESTAMP WITH TIME ZONE DEFAULT now(); >> ------------------------------------ >> >> 3- Then I added a constraint: >> >> --------------------------------- >> ALTER TABLE email.mailusers >> ADD CONSTRAINT mailuser_domain_id_fkey >> FOREIGN KEY (domain_id) >> REFERENCES email.domain(id) >> ON UPDATE CASCADE >> ON DELETE RESTRICT; >> ------------------------------------- >> >> >> Then I need to retrieve from psql to postfix this parameter value: >> - email adress . >> The email address is obviously something like a a concat (username,'@',domain). > > You can do a simple join between the tables (the string concatenation > operator is ||): > > select u.username || '@' || d.domain as email_address > from mailusers u inner join domain d on (u.domain_id = d.domain_id) > where ..... Hum hum... ------------------------------------------------------ SELECT u.username ||'@'||d.domain as email_address FROM email.mailusers u INNER JOIN email.domain d ON (u.domain_id=d.domain.id) WHERE id=1; ERROR: missing FROM-clause entry for table "domain" LINE 6: (u.domain_id=d.domain.id) -------------------------------------------------------------- What did I wrong following your solution? I found this, but again, it is not the expected result, even if not far: -------------------------------------------------------- SELECT username, domain_id FROM email.mailusers INNER JOIN email.domain ON email.mailusers.domain_id = email.domain.id; username | domain_id ---------------------+----------- MyUser.name | 1 ------------------------------------------------------ > > Note that "domain" is a reserved work, so you'll probably have either to > double-quote it or else rename that column to something else. > > Also, you really don't need so many id-type columns... given that the > domain and username are presumably unique in their respective tables, > having additional serial and domain_id columns seems like overkill. Why > not ditch them and use the domain name and username as the primary keys? Thank you very much for these hints, I will follow your advises. KISS principles are always good > > Ray. > > -- > Raymond O'Donnell :: Galway :: Ireland > rod@iol.ie -- google.com/+arnaudgabourygabx
On 03/02/2016 13:11, arnaud gaboury wrote: > Hum hum... > ------------------------------------------------------ > SELECT u.username ||'@'||d.domain as email_address > FROM email.mailusers u > INNER JOIN > email.domain d > ON > (u.domain_id=d.domain.id) > WHERE id=1; > > ERROR: missing FROM-clause entry for table "domain" > LINE 6: (u.domain_id=d.domain.id) > -------------------------------------------------------------- > > What did I wrong following your solution? In the join condition, replace "d.domain.id" with "d.id" (partly my mistake, I missed that the column is called "id" and not "domain_id" in the domains table). Ray. -- Raymond O'Donnell :: Galway :: Ireland rod@iol.ie
On Wed, Feb 3, 2016 at 2:19 PM, Raymond O'Donnell <rod@iol.ie> wrote: > On 03/02/2016 13:11, arnaud gaboury wrote: > >> Hum hum... >> ------------------------------------------------------ >> SELECT u.username ||'@'||d.domain as email_address >> FROM email.mailusers u >> INNER JOIN >> email.domain d >> ON >> (u.domain_id=d.domain.id) >> WHERE id=1; >> >> ERROR: missing FROM-clause entry for table "domain" >> LINE 6: (u.domain_id=d.domain.id) >> -------------------------------------------------------------- >> >> What did I wrong following your solution? > > In the join condition, replace "d.domain.id" with "d.id" (partly my > mistake, I missed that the column is called "id" and not "domain_id" in > the domains table). > > Ray. I noticed your mistake but made a wrong change myself :-( Now working perfectly: thetradinghall=> SELECT u.username ||'@'||d.domain as email_address FROM email.mailusers u INNER JOIN email.domainlist d ON (u.domain_id=d.id); email_address ----------------------------------- arnaud.gaboury@thetradinghall.com (1 row) ------------------------------------- As for the cleaning of ID, I dropped id and changed both primary keys. Thank you so much for your prompt answer and help. > > -- > Raymond O'Donnell :: Galway :: Ireland > rod@iol.ie -- google.com/+arnaudgabourygabx
On Wed, Feb 3, 2016 at 1:55 PM, Ricardo Ramírez <ricardojfr@gmail.com> wrote: > For resetting the id you may want to take a look at the sequence > manipulation functions [1] Problem has been solved by removing the id column. > > Regards, > Ricardo > > [1]http://www.postgresql.org/docs/current/static/functions-sequence.html > > > On Wed, Feb 3, 2016, 06:26 arnaud gaboury <arnaud.gaboury@gmail.com> wrote: >> >> On Wed, Feb 3, 2016 at 1:18 PM, arnaud gaboury <arnaud.gaboury@gmail.com> >> wrote: >> > $ psql -V >> > psql (PostgreSQL) 9.4.5 >> > >> > I am quite a newbie in psql. I am setting an email server and need to >> > create then query psql tables to get some information: mainly email >> > address and mail directory. >> > >> > For now I have created two tables this way. Both tables are in same >> > database and schema. I only insert one row in each. >> > >> > 1- the first one is just a list of all my domains. >> > >> > ----------------------------------------- >> > CREATE TABLE email.domain ( >> > id SERIAL, >> > domain TEXT NOT NULL, >> > PRIMARY KEY (id) >> > ); >> > --------------------------------- >> > >> > 2- second is a list of users >> > >> > -------------------------------------------------- >> > CREATE TABLE email.mailusers ( >> > id SERIAL PRIMARY KEY, >> > domain_id INTEGER DEFAULT 1, <<-- This ref to email.domain id=1 >> > password TEXT NOT NULL, >> > username TEXT UNIQUE NOT NULL, >> > created TIMESTAMP WITH TIME ZONE DEFAULT now(); >> > ------------------------------------ >> > >> > 3- Then I added a constraint: >> > >> > --------------------------------- >> > ALTER TABLE email.mailusers >> > ADD CONSTRAINT mailuser_domain_id_fkey >> > FOREIGN KEY (domain_id) >> > REFERENCES email.domain(id) >> > ON UPDATE CASCADE >> > ON DELETE RESTRICT; >> > ------------------------------------- >> > >> > >> > Then I need to retrieve from psql to postfix this parameter value: >> > - email adress . >> > The email address is obviously something like a a concat >> > (username,'@',domain). >> > >> > My first idea is to create a view (or materialized view ?) following >> > the principle described here[1] >> > >> > create view postfix_virtual as >> > select userid, userid as address from users >> > union all >> > select userid, address from virtual; >> > >> > , but I am a little lost when it comes to the UNION stuff (shall I use >> > it ?). >> > >> > Second possibility would be to create a modified query similar to >> > this[2]: >> > >> > query = SELECT concat(username,'@',domain) as email FROM users WHERE >> > username='%s' >> > >> > From now, I am able to create a view like this: >> > >> > --------------------------------------------- >> > CREATE VIEW email_address AS >> > SELECT * FROM >> > (SELECT username >> > FROM email.mailusers >> > WHERE id=2)a, >> > (SELECT domain >> > FROM email.domain >> > WHERE id=1)b; >> > --------------------------------- >> > I get a table: >> > username | domain >> > ---------------------+-------------------- >> > myuser.name | mydomain.com >> > >> > That's fine, but it is far from being generic and satisfying. >> > >> > Thank you for help and advises. >> > >> > [1]http://wiki2.dovecot.org/HowTo/DovecotPostgresql/ >> > [2]https://blog.za3k.com/installing-email-with-postfix-and-dovecot/ >> > >> EDIT: I deleted my first INSERT in table email.mailusers this way: >> >> DELETE * FROM email.mailusers >> >> , and now the id is set to 2. I would prefer having the id reset to 1. >> What is the correct way to get back id to 1 ? >> >> >> >> -- >> >> google.com/+arnaudgabourygabx >> >> >> -- >> Sent via pgsql-general mailing list (pgsql-general@postgresql.org) >> To make changes to your subscription: >> http://www.postgresql.org/mailpref/pgsql-general -- google.com/+arnaudgabourygabx
On 03/02/2016 13:57, arnaud gaboury wrote: > On Wed, Feb 3, 2016 at 2:19 PM, Raymond O'Donnell <rod@iol.ie> wrote: >> On 03/02/2016 13:11, arnaud gaboury wrote: >> >>> Hum hum... >>> ------------------------------------------------------ >>> SELECT u.username ||'@'||d.domain as email_address >>> FROM email.mailusers u >>> INNER JOIN >>> email.domain d >>> ON >>> (u.domain_id=d.domain.id) >>> WHERE id=1; >>> >>> ERROR: missing FROM-clause entry for table "domain" >>> LINE 6: (u.domain_id=d.domain.id) >>> -------------------------------------------------------------- >>> >>> What did I wrong following your solution? >> >> In the join condition, replace "d.domain.id" with "d.id" (partly my >> mistake, I missed that the column is called "id" and not "domain_id" in >> the domains table). >> >> Ray. > > I noticed your mistake but made a wrong change myself :-( > Now working perfectly: > > thetradinghall=> SELECT u.username ||'@'||d.domain as email_address > FROM email.mailusers u > INNER JOIN > email.domainlist d > ON > (u.domain_id=d.id); > > email_address > ----------------------------------- > arnaud.gaboury@thetradinghall.com > (1 row) > ------------------------------------- > > As for the cleaning of ID, I dropped id and changed both primary keys. > Thank you so much for your prompt answer and help. You're very welcome - glad to be able to help. R. -- Raymond O'Donnell :: Galway :: Ireland rod@iol.ie
>> >> thetradinghall=> SELECT u.username ||'@'||d.domain as email_address >> FROM email.mailusers u >> INNER JOIN >> email.domainlist d >> ON >> (u.domain_id=d.id); >> >> email_address >> ----------------------------------- >> arnaud.gaboury@thetradinghall.com >> (1 row) >> ------------------------------------- >> >> As for the cleaning of ID, I dropped id and changed both primary keys. >> Thank you so much for your prompt answer and help. In fact I kept the id for table domainlist (changed the name accordingly your advise). If I remove the id column, I will not be able anymore to do the above SELECT , no? The condition (u.domain_id=d.id) will no more be possible. Am I wrong? > > You're very welcome - glad to be able to help. > > R. > > > -- > Raymond O'Donnell :: Galway :: Ireland > rod@iol.ie -- google.com/+arnaudgabourygabx
On 03/02/2016 14:05, arnaud gaboury wrote: >>> >>> thetradinghall=> SELECT u.username ||'@'||d.domain as email_address >>> FROM email.mailusers u >>> INNER JOIN >>> email.domainlist d >>> ON >>> (u.domain_id=d.id); >>> >>> email_address >>> ----------------------------------- >>> arnaud.gaboury@thetradinghall.com >>> (1 row) >>> ------------------------------------- >>> >>> As for the cleaning of ID, I dropped id and changed both primary keys. >>> Thank you so much for your prompt answer and help. > > In fact I kept the id for table domainlist (changed the name > accordingly your advise). If I remove the id column, I will not be > able anymore to do the above SELECT , no? > The condition (u.domain_id=d.id) will no more be possible. > > Am I wrong? You're right - you'll need to use the domain name as the foreign key instead. So your tables will look like this: CREATE TABLE domains ( domain_name text not null primary key, .... ); CREATE TABLE mailusers ( username text not null, password text not null, domain_name text not null, created timestamp with time zone not null default now(), .... constraint users_pk primary key (username, domain_name), constraint users_domains_fk foreign key (domain_name) references domains(domain_name) ); And then your query would look something like this: select u.username ||'@'||d.domain as email_address from mailusers u inner join domains d on (u.domain_name = d.domain_name) ... HTH, Ray. -- Raymond O'Donnell :: Galway :: Ireland rod@iol.ie
On Wed, Feb 3, 2016 at 8:19 PM, Raymond O'Donnell <rod@iol.ie> wrote: > On 03/02/2016 14:05, arnaud gaboury wrote: >>>> >>>> thetradinghall=> SELECT u.username ||'@'||d.domain as email_address >>>> FROM email.mailusers u >>>> INNER JOIN >>>> email.domainlist d >>>> ON >>>> (u.domain_id=d.id); >>>> >>>> email_address >>>> ----------------------------------- >>>> arnaud.gaboury@thetradinghall.com >>>> (1 row) >>>> ------------------------------------- >>>> >>>> As for the cleaning of ID, I dropped id and changed both primary keys. >>>> Thank you so much for your prompt answer and help. >> >> In fact I kept the id for table domainlist (changed the name >> accordingly your advise). If I remove the id column, I will not be >> able anymore to do the above SELECT , no? >> The condition (u.domain_id=d.id) will no more be possible. >> >> Am I wrong? > > You're right - you'll need to use the domain name as the foreign key > instead. So your tables will look like this: > > CREATE TABLE domains ( > domain_name text not null primary key, > .... > ); > > CREATE TABLE mailusers ( > username text not null, > password text not null, > domain_name text not null, > created timestamp with time zone not null default now(), > .... > constraint users_pk primary key (username, domain_name), > constraint users_domains_fk foreign key (domain_name) > references domains(domain_name) > ); > > And then your query would look something like this: > > select u.username ||'@'||d.domain as email_address > from mailusers u > inner join domains d on (u.domain_name = d.domain_name) Very good. I changed tables accordingly. No more the id columns now. Thank you so much. > ... > > > HTH, > > Ray. > > -- > Raymond O'Donnell :: Galway :: Ireland > rod@iol.ie -- google.com/+arnaudgabourygabx