'Function that given a parameter will calculate a value from different tables using different logic

I am needing to create a view, and one of the columns in the view needs to calculate a value for the metric. The source table for a metric will be different depending on the metric_id, as will the logic for calculating the metric, although in all cases the return will always be a float. There are about 40 different metrics. Example view:

CREATE OR REPLEACE VIEW V_METRICS_MART AS
SELECT
METRIC_NAME,
REPORTING_PERIOD,
TEAM_NAME,
F_METRIC_VALUE(metric_id, reporting_period, team_id) FROM T_METRICS;

I did not want to create this as an ETL that would write the metric back to a table, as the underlying source data changes frequently, and I want the calculation to reflect the source as fresh as possible. (for performance this may be a materialized that gets built several times a day)

I could just have a huge CASE statement that does this, but as that seems difficult to maintain I was going to encapsulate each calculation into a separate function.

My question is, is there a way to quickly map function to a metric_id that is better than what I have? Ideally I don't want to have to modify the function every time there is a new metric. I was thinking something along the lines of a table that references the appropriate function, or even a table that maps a metric id to a sql statement, and a function that would run the query with the appropriate parameters. That way I could just maintain those queries on a table, instead of having to create a function for each one.

The queries that calculate the metric will use either reporting_period, or team_id, or both depending on the specific metric.

Below is my first attempt:

-- sample f_metric_value definition
CREATE OR REPLACE FUNCTION F_METRIC_VALUE(metric_id INTEGER, reporting_period DATE, team_id INTEGER) 
RETURN FLOAT DETERMINISTIC IS metric_value FLOAT;
BEGIN
    CASE metric_id
        WHEN 1 THEN metric_value := f_metric_foo(reporting_period);
        WHEN 2 THEN metric_value := f_metric_bar(reporting_period, team_id);
    END CASE;
    RETURN(metric_value);
END;

-- sample f_metric_foo
CREATE OR REPLACE FUNCTION f_metric_foo (reporting_period DATE)
 RETURN FLOAT DETERMINISTIC IS metric_value FLOAT;
 BEGIN
     SELECT VALUE_1 - VALUE_2 INTO metric_value FROM T_FOO WHERE transaction_dt = reporting_period;
     RETURN (metric_value);
 END;

--sample f_metric_bar
CREATE OR REPLACE FUNCTION f_metric_bar (reporting_period DATE, team_id INTEGER)
 RETURN FLOAT DETERMINISTIC IS metric_value FLOAT;
 BEGIN
     SELECT VALUE_1/VALUE_2 INTO metric_value FROM T_BAR where team = team_id and transaction_dt = reporting_period;
     RETURN (metric_value);
 END;


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source