【问题标题】:Postgres: select all row with count of a field greater than 1Postgres:选择字段计数大于1的所有行
【发布时间】:2016-04-01 14:24:43
【问题描述】:

我有一个存储产品价格信息的表,该表类似于,(不是主键)

no   name    price    date
1    paper   1.99     3-23
2    paper   2.99     5-25
3    paper   1.99     5-29
4    orange  4.56     4-23
5    apple   3.43     3-11

现在我想选择“名称”字段在表中多次出现的所有行。基本上,我希望我的查询返回前三行。

我试过了:

SELECT * FROM product_price_info GROUP BY name HAVING COUNT(*) > 1  

但我收到一条错误消息:

列“product_price_info.no​​”必须出现在 GROUP BY 子句中或用于聚合函数中

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:
    SELECT * 
    FROM product_price_info 
    WHERE name IN (SELECT name 
                   FROM product_price_info 
                   GROUP BY name HAVING COUNT(*) > 1)
    

    【讨论】:

    • 更好(如更快)使用例如COUNT(id) 根据官方文档。
    • 您可以在子查询中将“name”与 group by 连接,并使用“exists”子句而不是“in”。我认为它更快
    【解决方案2】:

    试试这个:

    SELECT no, name, price, "date"
    FROM (
      SELECT no, name, price, "date",
             COUNT(*) OVER (PARTITION BY name) AS cnt 
      FROM product_price_info ) AS t
    WHERE t.cnt > 1
    

    您可以使用COUNT 的窗口版本来获取每个name 分区的人口。然后,在外部查询中,过滤掉人口少于 2 的 name 分区。

    【讨论】:

    • 我已经在 SQLite3 中测试了 Juan Carlos Oropeza、Giorgos Betsos 和 jarlh 的版本。这个版本是最快的。它比其他两个快 26%。
    【解决方案3】:

    Window Functions 非常适合这个。

    SELECT p.*, count(*) OVER (PARTITION BY name) FROM product p;
    

    完整示例:

    CREATE TABLE product (no SERIAL, name text, price NUMERIC(8,2), date DATE);
    
    INSERT INTO product(name, price, date) values
    ('paper', 1.99, '2017-03-23'),
    ('paper', 2.99, '2017-05-25'),
    ('paper', 1.99, '2017-05-29'),
    ('orange', 4.56, '2017-04-23'),
    ('apple', 3.43, '2017-03-11')
    ;
    
    WITH report AS (
      SELECT p.*, count(*) OVER (PARTITION BY name) as count FROM product p
    )
    SELECT * FROM report WHERE count > 1;
    

    给予:

     no |  name  | price |    date    | count
    ----+--------+-------+------------+-------
      1 | paper  |  1.99 | 2017-03-23 |     3
      2 | paper  |  2.99 | 2017-05-25 |     3
      3 | paper  |  1.99 | 2017-05-29 |     3
    (3 rows)
    

    【讨论】:

    • 很好,但这并不能完全回答 op 的问题
    • @Madbreaks 感谢您的关注。我更新了答案。
    【解决方案4】:

    自连接版本,使用返回多次出现的名称的子查询。

    select t1.*
    from tablename t1
    join (select name from tablename group by name having count(*) > 1) t2
      on t1.name = t2.name
    

    IN/EXISTS 版本基本相同,但可能要快一些。

    【讨论】:

      猜你喜欢
      • 2012-04-03
      • 1970-01-01
      • 2012-08-10
      • 1970-01-01
      • 1970-01-01
      • 2011-04-12
      • 2012-06-24
      • 2021-04-24
      • 2021-07-21
      相关资源
      最近更新 更多