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
SELECT *
FROM product_price_info
WHERE name IN (SELECT name
FROM product_price_info
GROUP BY name HAVING COUNT(*) > 1)
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.
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)
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.