[postgis-users] pl/pgsql question: dynamic access to record.column

Dylan Beaudette dylan.beaudette at gmail.com
Wed Jan 10 14:04:10 PST 2007


On Wednesday 10 January 2007 13:10, Mark Cave-Ayland wrote:
> On Wed, 2007-01-10 at 12:24 -0800, Dylan Beaudette wrote:
> > I am learning how to use PL/PGSQL and have come upon something that I
> > just don't seem to be able to solve on my own.
> >
> > I have a function, which takes a column name as an argument. A FOR loop
> > iterates over rows, using a RECORD datatype to store each iteration of
> > the loop.
> >
> > If I hard-code in a column name into some calculation, things work fine.
> > However, I cannot seem to figure out how to _dynamically_ access a column
> > from a RECORD datatype:
> >
> > -- this works fine : 'field_pct_clay' is a hard-coded column name
> > DEFINE
> > hz_record RECORD;
> > wt_column FLOAT;
> > thick FLOAT;
> > ...
> > wt_column := wt_column + (hz_record.field_pct_clay * thick) ;
> >
> > -- this does not work: 'the_column' is an argument to the function being
> > defined:
> >
> > wt_column := wt_column + (hz_record.the_column * thick) ;
> >                                                             ^^^^^^^^^^^^^
> >
> > obviously, the interpreter tells me that there is no column named
> > 'the_column' in the RECORD iterator...
> >
> > Searching on google, it seems that a dynamic expression like this needs
> > to be evaluated with the EXECUTE keyword.... However something like this
> > does not work:
> >
> > wt_column := EXECUTE 'wt_column + (hz_record.' || quote_ident(the_column)
> > || ' * thick)' ;
> >
> > any tips would be a great help!
> >
> > thanks!
>
> Hi Dylan,
>
> You'll need to post the entire stored procedure for this one so that we
> can tell the difference between PL/PGSQL variables and column names.
>
>
> Kind regards,
>
> Mark.

Thanks Mark, please find the entire procedure below:

-------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION depth_wt_avg (
	the_pedon_id varchar, top_lim numeric, bottom_lim numeric, the_column 
varchar )
	RETURNS FLOAT as $$
	DECLARE

-- horizon variables, use a record datatype
	hz_record RECORD;
	
	thick FLOAT :=0 ;
	thick_total FLOAT :=0 ;
	
	wt_column FLOAT :=0 ;
	wt_column_avg FLOAT :=0 ;
	
	
--	flags detecting when the defined limits intersects a horizon
	intersects_top_flag integer ;
	intersects_bottom_flag integer ;
	
	BEGIN
		
		FOR hz_record in 
			EXECUTE 'select top, bottom, ' 
			|| quote_ident(the_column)
			|| ' from horizon '
			|| ' where pedon_id = '
			|| quote_literal(the_pedon_id) 
			|| ' and ( bottom >= '
			|| top_lim 
			|| ' and top <= '
			|| bottom_lim
			|| ' ) '
			|| ' and '
			|| quote_ident(the_column)
			|| ' is not null'
			|| ' order by top '
			LOOP 
			
-- 			use something like this for each horizon, to create 
PCS_intersects_top_flag, PCS_intersects_bottom_flag
 			select into intersects_top_flag
				CASE WHEN top_lim > hz_record.top and top_lim < hz_record.bottom THEN 1 
ELSE 0 END ;

 			select into intersects_bottom_flag
				CASE WHEN bottom_lim > hz_record.top and bottom_lim < hz_record.bottom 
THEN 1 ELSE 0 END ;			
			
-- 			if the PCS does not overlap this horizon
			thick := hz_record.bottom - hz_record.top ;

-- 			else use the top of the PCS instead			
			IF intersects_top_flag = 1 THEN
				thick := hz_record.bottom - top_lim ;
			END IF;
			
-- 			else if we are at the last horizon use the bottom of the PCS as the 
bottom cutoff
			IF intersects_bottom_flag = 1 THEN
				thick := bottom_lim - hz_record.top ;
			END IF;
			
--			sum the horizon thickness within the PCS 
			thick_total := thick_total + thick;

--			the weighted clay percent, and frags pct
			EXECUTE 'select ' || wt_column || ' + (' || 'hz_record' || '.' || 
quote_ident(the_column) || ' * ' || thick || ')' into wt_column;
			
--			the weighted-avg clay percent and frags within the PCS
			wt_column_avg := wt_column / thick_total;
			
			
		END LOOP;
		
		RETURN round(wt_column_avg::numeric, 1) ;
		
	END
$$ LANGUAGE plpgsql;

-------------------------------------------------------------------------------------
-- 
Dylan Beaudette
Soils and Biogeochemistry Graduate Group
University of California at Davis
530.754.7341



More information about the postgis-users mailing list