Abishek Arumugam R
Abishek Arumugam R

Reputation: 57

Formula Query on PostgreSQL

My input data is like this

wavelength   reflectance
341.6        1.15  
343.1        1.14
344.7        1.13
346.3        1.14
347.9        1.14
349.5        1.12
351.1        1.12
352.6        1.13
354.2        1.13

I am using this formula Query

WITH CTE AS(
    SELECT 
      ROW_NUMBER() OVER(    
        PARTITION BY CAST(wavelength AS INT)
                     -CAST(wavelength AS INT)%5
        ORDER BY wavelength) AS ROW_ID,
      wavelength,
      avg( reflectance ) OVER(
        PARTITION BY CAST(wavelength AS INT)
                     -CAST(wavelength AS INT)%5
        ORDER BY wavelength
        rows BETWEEN 1 FOLLOWING
             and UNBOUNDED FOLLOWING) As reflectance 
      FROM 
      test
    )
    select trunc(wavelength/5)*5 AS wavelengthwavelength, reflectance
    from CTE
    where row_id = 1

In this query it povides the output like this

wavelength  reflectance
340         2.6400000000000000
340         2.5200000000000000
345         2.5200000000000000
355         2.5500000000000000
360         2.4250000000000000
365         2.4650000000000000
365         2.5450000000000000
370         2.4733333333333333
380         2.6600000000000000
385         2.7400000000000000
390         2.7700000000000000
390         2.8833333333333333

In this output 340,365,390 is placed as twice, instead of placed as twice it should be placed as once only based on the min value, how should do this...

Upvotes: 0

Views: 167

Answers (3)

Erwin Brandstetter
Erwin Brandstetter

Reputation: 657942

WITH cte AS(
   SELECT row_number() OVER(PARTITION BY wavelength::int - wavelength::int%5
                            ORDER BY wavelength) AS row_id,
          wavelength,
          avg(reflectance) OVER(PARTITION BY wavelength::int - wavelength::int%5
                           ORDER BY wavelength
                           ROWS BETWEEN 1 FOLLOWING
                           AND UNBOUNDED FOLLOWING) AS reflectance 
   FROM   test
   )
SELECT DISTINCT ON (1)
       trunc(wavelength/5)*5 AS wavelength, reflectance
FROM   cte
WHERE  row_id = 1
ORDER  BY 1, 2;

DISTINCT ON is a Postgres extension to standard SQL DISITNCT and is particularly useful if you want to add more columns and still pick the row with minimum reflectance. Otherwise GROUP BY can to the job as well.

More details in this related answer:
Select first row in each GROUP BY group?

With DISTINCT ON, you need ORDER BY in the final SELECT. However, you will want to add that either way. Per documentation:

Currently, window functions always require presorted data, and so the query output will be ordered according to one or another of the window functions' PARTITION BY/ORDER BY clauses. It is not recommended to rely on this, however. Use an explicit top-level ORDER BY clause if you want to be sure the results are sorted in a particular way.

Upvotes: 1

StanislavL
StanislavL

Reputation: 57421

select wavelength, MIN(reflectance) 
FROM (select trunc(wavelength/5)*5 AS wavelength, reflectance
    from CTE
    where row_id = 1) src
GROUP BY wavelength 

Upvotes: 0

Hamidreza
Hamidreza

Reputation: 3128

I think that the best way is that you use trunc(wavelength) exchange of trunc(wavelength/5)*5 but if you don't want to do that you can do something like this:

select trunc(trunc(wavelength * 5) / 5) AS wavelengthwavelength, reflectance
from CTE
where row_id = 1

Upvotes: 0

Related Questions