web-dev-qa-db-fra.com

Postgres: sélectionnez toutes les lignes avec un nombre de champs supérieur à 1

j'ai un tableau contenant des informations sur les prix des produits, le tableau ressemble à (non est la clé primaire)

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

en ce moment, je veux sélectionner toutes les lignes où le champ "nom" est apparu plusieurs fois dans le tableau. Fondamentalement, je veux que ma requête renvoie les trois premières lignes.

J'ai essayé:

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

mais je reçois une erreur disant:

la colonne "product_price_info.no" doit apparaître dans la clause GROUP BY ou être utilisée dans une fonction d'agrégation

14
user2628641
SELECT * 
FROM product_price_info 
WHERE name IN (SELECT name 
               FROM product_price_info 
               GROUP BY name HAVING COUNT(*) > 1)
26

Essaye ça:

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

Vous pouvez utiliser la version Windows de COUNT pour obtenir la population de chaque name partition. Ensuite, dans une requête externe, filtrez les partitions name ayant une population inférieure à 2.

7
Giorgos Betsos

Fonctions de fenêtre sont vraiment bien pour cela.

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

Pour un exemple complet:

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;

Donne:

 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)
5
Jeff C Johnson

Version auto-jointe, utilisez une sous-requête qui renvoie le nom qui apparaît plus d'une fois.

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

Fondamentalement les mêmes que les versions IN/EXISTS, mais probablement un peu plus rapidement.

2
jarlh