如何避免查询中重复的数据?

时间:2017-07-07 20:38:23

标签: sql postgresql left-join

创建一个返回动态结果的查询的最佳方法是什么,在我的postgresql中我有三个表:

contacts |contact_emails| contact_numbers
id       | id           | id
descrip  | id_contact   | id_contact
name     | email        | number

我希望创建一个类似的结果:

contact_name| contact_emailx| contact_numbersx

那些“x”是电子邮件和可以有联系人的号码

我正在尝试使用左连接,这是我的代码:

SELECT c.id, c.contact_name, cn.number, ce.email 
FROM contacts c 
LEFT JOIN contact_numbers cn ON c.id = cn.contact_id 
LEFT JOIN contact_emails ce ON c.id = ce.contact_id 
WHERE c.user_id = 1

但它会返回enter image description here

我期待的是:

 contact_name |number1  | number2  |email
LA MEJOR      | 25445877| 25845877 |AMEJOR@GMAIL.COM 

 contact_name    |number1  | number2  |email1          | email2
EDIFICADORA JUANA| 24602254| 55655545 |oipoa@gmaio.com |rst008@guan.com

我感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

您可以使用PostgreSQL array_agg将所有电子邮件和所有数字汇总到两个数组中:

SELECT 
    c.id, c.contact_name, array_agg(DISTINCT cn.number) AS numbers, array_agg(DISTINCT ce.email) AS emails
FROM 
    contacts c 
    LEFT JOIN contact_numbers cn ON c.id = cn.contact_id 
    LEFT JOIN contact_emails ce  ON c.id = ce.contact_id 
WHERE 
    c.user_id = 1
GROUP BY
    c.id
ORDER BY
    c.id ;
id | contact_name      | numbers             | emails                             
-: | :---------------- | :------------------ | :----------------------------------
 2 | LA MEJOR          | {25445877}          | {AHEJOR@GMAIL.COM,AMEJOR@GMAIL.COM}
 3 | EDIFICADORA JUANA | {24602254}          | {oipoa@gmaio.com,rst008@guan.com}  
 4 | EDIFICADORA JUANA | {24602254,55655545} | {oipoa@gmaio.com,rst008@guan.com}  
 5 | EDIFICADORA JUANA | {24602254,55655545} | {oipoa@gmaio.com,rst008@guan.com}  

作为替代方案,您可以使用子查询(在某些情况下可能更快):

SELECT 
    c.id, c.contact_name, 
    (SELECT array_agg(DISTINCT cn.number) FROM contact_numbers cn WHERE cn.contact_id = c.id) AS numbers, 
    (SELECT array_agg(DISTINCT ce.email)  FROM contact_emails  ce WHERE ce.contact_id = c.id) AS emails
FROM 
    contacts c 
WHERE 
    c.user_id = 1 
ORDER BY
    c.id ;
id | contact_name      | numbers             | emails                             
-: | :---------------- | :------------------ | :----------------------------------
 2 | LA MEJOR          | {25445877}          | {AHEJOR@GMAIL.COM,AMEJOR@GMAIL.COM}
 3 | EDIFICADORA JUANA | {24602254}          | {oipoa@gmaio.com,rst008@guan.com}  
 4 | EDIFICADORA JUANA | {24602254,55655545} | {oipoa@gmaio.com,rst008@guan.com}  
 5 | EDIFICADORA JUANA | {24602254,55655545} | {oipoa@gmaio.com,rst008@guan.com}  

如果你想分开(第一个)两个电子邮件和号码,你可以通过结束上一个查询来完成:

SELECT
    id, contact_name, 
    numbers[1] AS number1,
    numbers[2] AS number2,
    emails[1]  AS email1,
    emails[2]  AS email2
FROM
(
    SELECT 
        c.id, c.contact_name, 
        (SELECT array_agg(DISTINCT cn.number) FROM contact_numbers cn WHERE cn.contact_id = c.id) AS numbers, 
        (SELECT array_agg(DISTINCT ce.email)  FROM contact_emails  ce WHERE ce.contact_id = c.id) AS emails
    FROM 
        contacts c 
    WHERE 
        c.user_id = 1 
) AS q
ORDER BY
    id ;
id | contact_name      |  number1 |  number2 | email1           | email2          
-: | :---------------- | -------: | -------: | :--------------- | :---------------
 2 | LA MEJOR          | 25445877 |     null | AHEJOR@GMAIL.COM | AMEJOR@GMAIL.COM
 3 | EDIFICADORA JUANA | 24602254 |     null | oipoa@gmaio.com  | rst008@guan.com 
 4 | EDIFICADORA JUANA | 24602254 | 55655545 | oipoa@gmaio.com  | rst008@guan.com 
 5 | EDIFICADORA JUANA | 24602254 | 55655545 | oipoa@gmaio.com  | rst008@guan.com 

您可以在 dbfiddle here

在线查看所有内容

使用的表格和数据:

CREATE TABLE contacts
(
    id INTEGER PRIMARY KEY,
    user_id INTEGER NOT NULL /* REFERENCES users(id) */,
    descrip text,
    contact_name character varying(255)
) ;

CREATE TABLE contact_emails
(
    contact_id  INTEGER NOT NULL REFERENCES contacts(id),
    email character varying(255) NOT NULL,
    PRIMARY KEY(contact_id, email)   -- This is the natural key for this table, no need for synthetic id
) ;

CREATE TABLE contact_numbers
(
    contact_id  INTEGER NOT NULL REFERENCES contacts(id),
    number integer,
    PRIMARY KEY(contact_id, number)   -- Again...
) ;

...和数据

INSERT INTO 
    contacts
    (id, user_id, descrip, contact_name)
VALUES
    (2, 1, '', 'LA MEJOR'),
    (3, 1, '', 'EDIFICADORA JUANA'),
    (4, 1, '', 'EDIFICADORA JUANA'),
    (5, 1, '', 'EDIFICADORA JUANA') ;

INSERT INTO
    contact_emails
    (contact_id, email)
VALUES
    (2, 'AMEJOR@GMAIL.COM'),
    (2, 'AHEJOR@GMAIL.COM'),
    (3, 'oipoa@gmaio.com'),
    (3, 'rst008@guan.com'),
    (4, 'oipoa@gmaio.com'),
    (4, 'rst008@guan.com'),
    (5, 'oipoa@gmaio.com'),
    (5, 'rst008@guan.com') ;

INSERT INTO
    contact_numbers
    (contact_id, number)
VALUES
    (2, '25445877'),
    (3, '24602254'),
    (4, '24602254'),
    (4, '55655545'),
    (5, '24602254'),
    (5, '55655545') ;

注意:图像数据中存在大量重复值。