web-dev-qa-db-fra.com

Compter les valeurs distinctes avec OVER (PARTITION BY id)

Est-il possible de compter des valeurs distinctes en conjonction avec des fonctions de fenêtre telles que OVER(PARTITION BY id)? Actuellement, ma requête est la suivante:

SELECT congestion.date, congestion.week_nb, congestion.id_congestion,
   congestion.id_element,
ROW_NUMBER() OVER(
    PARTITION BY congestion.id_element
    ORDER BY congestion.date),
COUNT(DISTINCT congestion.week_nb) OVER(
    PARTITION BY congestion.id_element
) AS week_count
FROM congestion
WHERE congestion.date >= '2014.01.01'
AND congestion.date <= '2014.12.31'
ORDER BY id_element, date

Cependant, lorsque j'essaie d'exécuter la requête, l'erreur suivante apparaît:

"COUNT(DISTINCT": "DISTINCT is not implemented for window functions"
12
user007

Non, comme l'indique le message d'erreur, DISTINCT n'est pas implémenté avec les fonctions Windows. En utilisant les informations de ce lien dans votre cas, vous pouvez utiliser quelque chose comme:

WITH uniques AS (
 SELECT congestion.id_element, COUNT(DISTINCT congestion.week_nb) AS unique_references
 FROM congestion
WHERE congestion.date >= '2014.01.01'
AND congestion.date <= '2014.12.31'
 GROUP BY congestion.id_element
)

SELECT congestion.date, congestion.week_nb, congestion.id_congestion,
   congestion.id_element,
ROW_NUMBER() OVER(
    PARTITION BY congestion.id_element
    ORDER BY congestion.date),
uniques.unique_references AS week_count
FROM congestion
JOIN uniques USING (id_element)
WHERE congestion.date >= '2014.01.01'
AND congestion.date <= '2014.12.31'
ORDER BY id_element, date

Selon la situation, vous pouvez également placer une sous-requête directement dans la liste SELECT-:

SELECT congestion.date, congestion.week_nb, congestion.id_congestion,
   congestion.id_element,
ROW_NUMBER() OVER(
    PARTITION BY congestion.id_element
    ORDER BY congestion.date),
(SELECT COUNT(DISTINCT dist_con.week_nb)
    FROM congestion AS dist_con
    WHERE dist_con.date >= '2014.01.01'
    AND dist_con.date <= '2014.12.31'
    AND dist_con.id_element = congestion.id_element) AS week_count
FROM congestion
WHERE congestion.date >= '2014.01.01'
AND congestion.date <= '2014.12.31'
ORDER BY id_element, date
3
Simo Kivistö

Je trouve que le moyen le plus simple consiste à utiliser une sous-requête/CTE et une agrégation conditionnelle:

SELECT c.date, c.week_nb, c.id_congestion, c.id_element,
       ROW_NUMBER() OVER (PARTITION BY c.id_element ORDER BY c.date),
       (CASE WHEN seqnum = 1 THEN 1 ELSE 0 END) as week_count
FROM (SELECT c.*,
             ROW_NUMBER() OVER (PARTITION BY c.congestion.id_element, c.week_nb
                                ORDER BY c.date) as seqnum
      FROM congestion c
     ) c
WHERE c.date >= '2014.01.01' AND c.date <= '2014.12.31'
ORDER BY id_element, date
0
Gordon Linoff