2016-04-01 39 views
3

我有表,用于存储产品的价格信息,该表类似于计数,(没有是主键)Postgres的:选择所有的行与现场大于1

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子句或聚合函数中使用

回答

6
SELECT * 
FROM product_price_info 
WHERE name IN (SELECT name 
       FROM product_price_info 
       GROUP BY name HAVING COUNT(*) > 1) 
4

试试这个:

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分区的填充。然后,在外部查询中,筛选出name群体小于2的分区。

2

自加入版本使用的子查询返回出现多次的名称。

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

基本上一样IN/EXISTS版本,但可能有点快。

0

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') 
; 

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

给出:

no | name | price | date | count 
----+--------+-------+------------+------- 
    5 | apple | 3.43 | 2017-03-11 |  1 
    4 | orange | 4.56 | 2017-04-23 |  1 
    1 | paper | 1.99 | 2017-03-23 |  3 
    2 | paper | 2.99 | 2017-05-25 |  3 
    3 | paper | 1.99 | 2017-05-29 |  3 
(5 rows)