PostgreSQL - 如何在使用WHERE子句进行LEFT OUTER JOIN时删除重复项?

时间:2017-01-19 12:16:06

标签: sql postgresql join left-join

我有两张桌子:

users table
+--------+---------+
| id     | integer |
+--------+---------+
| phone  | string  |
+--------+---------+
| active | boolean |
+--------+---------+

statuses table
+---------+---------+
| id      | integer |
+---------+---------+
| user_id | integer |
+---------+---------+
| step_1  | boolean |
+---------+---------+
| step_2  | boolean |
+---------+---------+

我正在LEFT OUTER JOIN表上statuses usersWHERE这样的句子:

SELECT users.id, statuses.step_1, statuses.step_2
FROM users 
LEFT OUTER JOIN statuses ON users.id = statuses.user_id
WHERE (users.active='f')
ORDER BY users.id DESC

我的问题

有些用户在users表格中有相同的电话号码,我想根据电话号码删除重复的用户。

我不想从数据库中删除它们。但只想将它们排除在此查询之外。

例如,约翰(身份证号码1)和莎拉(身份证号码2)分享相同的电话号码(+ 6012-3456789),删除其中一个,约翰或萨拉对我来说没问题。

我尝试了但是没有用?

首先:

SELECT DISTINCT users.phone
FROM users 
LEFT OUTER JOIN statuses ON users.id = statuses.user_id
WHERE (users.active='f')
ORDER BY users.id DESC

第二:

SELECT users.phone, COUNT(*)
FROM users
LEFT OUTER JOIN statuses ON users.id = statuses.user_id    
WHERE (users.active='f')
GROUP BY phone
HAVING COUNT(users.phone) > 1

2 个答案:

答案 0 :(得分:1)

我会在进行连接之前执行此操作。在Postgres中,select distinct on是一个非常有用的结构:

SELECT u.id, s.step_1, s.step_2
FROM (SELECT distinct on (phone) u.*
      FROM users u
      WHERE u.active = 'f'
      ORDER BY phone
     ) u LEFT OUTER JOIN
     statuses s
     ON u.id = s.user_id
WHERE u.active = 'f'
ORDER BY u.id DESC;

distinct on为括号中的任何内容返回一行。在这种情况下,这将是phone(基于"我想根据电话号码删除重复的用户")。然后,join不应将这些显示为重复项。

答案 1 :(得分:0)

这是一种方式

自我加入用户表并使用电话号码加入,并按比较运算符过滤任何一个重复的名称。

SELECT *
FROM   (SELECT u.*
        FROM   users u
               JOIN users u1
                 ON u. u.phone = u1.phone -- to 
                    AND u.name >= u1.name) u
       LEFT OUTER JOIN statuses
                    ON users.id = statuses.user_id
WHERE  ( users.active = 'f' )

或使用ROW_NUMBER

为每个电话号码生成行号,并过滤第一个电话号码,行号为1

SELECT *
FROM   (SELECT u.*,
               Row_number()OVER(partition BY phone ORDER BY name) rn
        FROM   users u) u
       LEFT OUTER JOIN statuses
                    ON users.id = statuses.user_id
WHERE  ( users.active = 'f' )
       AND rn = 1