views:

32

answers:

1

Problem

In the following query, plr_stations is called twice:

  1. once to limit the WHERE clause; and
  2. once to count the number of results it returned.

The code resembles:

  SELECT
 m.*,
 s.*,
 (
  SELECT
    count(1)
  FROM
    climate.plr_stations('48.5146','-123.4447')
 ) AS count_stations
  FROM 
 climate.station s,
 climate.measurement m,
 (
  SELECT
    id
  FROM
    climate.plr_stations('48.5146','-123.4447')
 ) stations
  WHERE
    s.applicable AND
    s.id = stations.id AND
    m.station_id = s.id AND ...

The results of this query are then aggregated by a date query.

Solutions

Populate a temporary table, or an array variable, with the results from the function call.

Update #1

The function call will randomly select a sample of stations if too many stations are inside the spherical polygon defined by the parameters to the function call.

Update #2

The date query aggregation that starts the full query looks as follows:

        SELECT 
          extract(YEAR FROM m.taken) AS year_taken,
          avg(m.amount) AS amount,
          count(m.amount) AS count_measurements,
          md.count_stations,
          min(md.elevation) AS elevation_min,
          max(md.elevation) AS elevation_max
        FROM
          climate.measurement m, (
          SELECT
            m.*,
            s.*, ...

Question

How else can the redundant call be eliminated?

Thank you.

+2  A: 

Doubtful that it would fold that given that it shouldn't be marked as IMMUTABLE (if I understand the intent as such).

Something along this line should work...depending on your requirements...

with R_stations as (
SELECT
     id,   
     count(1) over () c
      FROM
        climate.plr_stations('48.5146','-123.4447')
)
     SELECT
     m.*,
     s.*,
     stations.c count_stations
      FROM 
     climate.station s,
     climate.measurement m,
     R_stations stations
      WHERE
        s.applicable AND
        s.id = stations.id AND
        m.station_id = s.id AND ...

But it may be easier considering your aggregation to just do this...

 SELECT
 m.*,
 s.*,
 stations.c count_stations
  FROM 
 climate.station s,
 climate.measurement m,
 (SELECT
 id,   
 count(1) over () c
  FROM
    climate.plr_stations('48.5146','-123.4447')

) stations
      WHERE
        s.applicable AND
        s.id = stations.id AND
        m.station_id = s.id AND ...
rfusca
I think you can even get rid of that sub select and make it just a "stations.c", but without running it, i'm not 100%. (I made this change.)
rfusca
You don't *need* to use WITH here, it just makes it easier to read in imho.
rfusca
@Dave Jarvis: if you just change the WITH (Select...) in my query to a normal derived portion, then you should be able to embed it appropriately.
rfusca
@rfusca: Yes, I can remove the `WITH` clause entirely and embed the sub-select naturally. Thank you again.
Dave Jarvis