4

我有一张桌子,里面有一个地址。我想选择与另一个帐户位于同一地址的每个帐户。

如果我的数据看起来像这样:

------------------------------------
| Account Number | Address          |
| 12345          | 55 Bee St        |
| 23456          | 94 Water way     |
| 34567          | 15 Beagle Drive  |
| 45678          | 55 Bee St        |
| 56789          | 94 Water way     |
| 67890          | 12 Green St      |
-------------------------------------

我想做一些类似的事情:

SELECT * FROM accounts WHERE group by address > 1;

这样我的结果将是:

------------------------------------
| Account Number | Address          |
| 12345          | 55 Bee St        |
| 23456          | 94 Water way     |
| 45678          | 55 Bee St        |
| 56789          | 94 Water way     |
-------------------------------------

如果有什么不同,那就是 PostgreSQL 数据库。

4

6 回答 6

1

您需要使用两个地址相同但确保两行之间的帐号不同的连接条件将表连接到自身:

select distinct account_number, address
from accounts a1
join accounts a2 on a1.account_number > a2.account_number
   and a1.address = a2.address

请注意使用>帐号之间的比较,这不仅可以防止行连接到自身,还可以防止反向连接。

我添加distinct了以防三个帐户具有相同的地址,否则您不需要它。

于 2013-03-28T01:57:31.790 回答
1

对同一张表进行左连接,找到地址相同的记录,并按字段分组,然后可以统计匹配的地址,得到至少有一个匹配地址的记录:

select a.AccountNumber, a.Address
from accounts a
left join accounts o on o.Address = a.Address and o.AccountNumber <> a.AccountNumber
group by a.AccountNumber, a.Address
having count(o.AccountNumber) >= 1

这种方法为您提供每个帐号的地址,并且如果地址出现两次以上,它不会给您重复。

于 2013-03-28T02:05:04.367 回答
1

这应该可以解决问题:

SELECT *
FROM Account A1
WHERE
    EXISTS (
        SELECT *
        FROM Account A2
        WHERE
            A1.AccountNumber <> A2.AccountNumber
            AND A1.Address = A2.Address
    )

简而言之:选择每个帐户,以便有一个不同的帐户 ( A1.AccountNumber <> A2.AccountNumber) 具有相同的地址 ( A1.Address = A2.Address)。

于 2013-03-28T02:13:36.650 回答
1

这是展示三个有效答案的性能的测试。
EXISTS优于带有LEFT JOIN/的那个GROUP BY

测试设置

具有 100k 行的表,有 1000 个不同的值b
性能差距随着行数的增加而扩大 - 更少的重复意味着更少的差异。
没有索引。

CREATE TABLE tbl (a text, b text);
INSERT INTO tbl
SELECT (random()*10000)::int::text
      ,(random()*1000)::int || ' some more text here'
FROM   generate_series(1, 100000) g;

1. @古法LEFT JOIN//GROUP BYHAVING

EXPLAIN ANALYZE
SELECT t.a, t.b
FROM   tbl t
LEFT   join tbl t2 on t2.b = t.b and t2.a <> t.a
GROUP  by t.a, t.b
HAVING count(t2.a) >= 1;

2. 相同的,解开的只是JOIN/GROUP BY

EXPLAIN ANALYZE
SELECT t.a, t.b
FROM   tbl t
JOIN   tbl t2 ON t2.b = t.b AND t2.a <> t.a
GROUP  BY t.a, t.b;

3. @布兰科EXISTS

EXPLAIN ANALYZE
SELECT *
FROM   tbl t
WHERE  EXISTS (
    SELECT *
    FROM   tbl t2
    WHERE  t2.a <> t.a
    AND    t2.b = t.b
    );

4. @波西米亚DISTINCT

EXPLAIN ANALYZE
SELECT DISTINCT t.a, t.b
FROM   tbl t
JOIN   tbl t2 on t2.b = t.b and t2.a <> t.a;

-> SQLfiddle显示查询的 EXPLAIN ANALYZE 输出

  1. 总运行时间:12208.954 毫秒
  2. 总运行时间:11504.460 毫秒
  3. 总运行时间:272.508 毫秒——!~ 比 1 快 45 倍。
  4. 总运行时间:11540.627 毫秒

添加多列索引(SQLfiddle)后..

CREATE INDEX a_b_idx ON tbl(b, a);

..运行时不会改变。Postgres 不使用索引。它显然希望顺序表扫描更快,因为无论如何都必须读取整个表。

除了执行时间,还要注意行数,这证明了我所讨论
的观点: JOIN 创建了很多中间重复项,EXISTS版本开始避免这些重复项:

输出EXPLAIN ANALYZE1.

HashAggregate(成本=230601.26..230726.26 行=10000 宽度=31)(实际时间=12127.090..12183.087 行=99476 循环=1)
过滤器:(计数(t2.a)> = 1)
-> Hash Left Join (cost=3670.00..154661.89 rows=10125250 width=31) (实际时间=99.591..5897.744 rows=9991102 loops=1)
哈希条件:(tb = t2.b)
加入过滤器:(t2.a ta)
加入过滤器删除的行:101052
-> Seq Scan on tbl t (cost=0.00..1736.00 rows=100000 width=27) (实际时间=0.036..36.197 rows=100000 loops=1)
-> 哈希(成本=1736.00..1736.00 行=100000 宽度=27)(实际时间=99.141..99.141 行=100000 循环=1)
存储桶:2048 批次:8 内存使用量:784kB
-> tbl t2 上的 Seq Scan(成本=0.00..1736.00 行=100000 宽度=27)(实际时间=0.004..44.899 行=100000 循环=1)
总运行时间:12208.954 毫秒

3的输出EXPLAIN ANALYZE。:

Hash Semi Join (cost=3670.00..7783.00 rows=1 width=27) (实际时间=81.630..247.371 rows=100000 loops=1)
哈希条件:(tb = t2.b)
加入过滤器:(t2.a ta)
加入过滤器删除的行数:1009
-> Seq Scan on tbl t (cost=0.00..1736.00 rows=100000 width=27) (实际时间=0.010..32.758 rows=100000 loops=1)
-> 哈希(成本=1736.00..1736.00 行=100000 宽度=27)(实际时间=81.388..81.388 行=100000 循环=1)
存储桶:2048 批次:8 内存使用量:784kB
-> tbl t2 上的 Seq Scan(成本=0.00..1736.00 行=100000 宽度=27)(实际时间=0.003..32.114 行=100000 循环=1)
总运行时间:272.508 毫秒
于 2013-03-28T11:35:13.223 回答
0

你想要一个HAVING子句:

SELECT * FROM accounts
GROUP BY address
HAVING COUNT(address) > 1;
于 2013-03-28T01:56:48.737 回答
0

我相信您正在寻找 HAVING 子句:

 select address,sum(accountnumber) group by address having sum(accountnumber) >1
于 2013-03-28T01:59:43.947 回答