smh...
smh...
I’ve generally used it as a step in a data pipeline, where some intermittent state or aggregation where being stale/stable for a period of time is ok. Did this recently for a daily trends report on some news data - live querying the data is slow, but baking it off into a MV makes it much faster and keeps the query result from changing too rapidly to new data.
This is outdated; most modern DBs treat views as they would CTEs. If you don’t reference a defined field downstream, it doesn’t need to get calculated.
(Or maybe my knowledge is outdated and the optimizers have gotten way better than they were 3-4 years ago.)
Imagine wanting something as simple as "find_percentile_value(table, column, percentile)". There is no portable and standard way to write this parametric abstraction and then reuse it on any column source you need to interrogate later.
Now, ... reuse. Surely you write the result to another table and then refer to that.
Note, this was just meant as an example where a view is not helpful. We don't always desire particular calculated data to be named for reuse. Rather, we want a reusable method we can apply to any data. In my earlier post, I tried to address the topic of macros or generated SQL, and so suggested it take a table and column name as input to expand a query idiom for a set of values stored in a table. But, that's not how I'd really want to do it. The rest of this comment will veer into a more elaborate perspective on real functional libraries, rather than mere macros...
Today, with dialect-specific mechanisms, I can try to define window functions or ordered-set aggregate functions. It would be possible to solve the percentile problem this way. In fact, many SQL dialects have built-in functions that can help with percentiles, since this is recognized as such a basic statistical concept. But, I only chose percentile as an accessible yet concrete example. These built-in solutions are not the answer to my question. My question is how can user programmers extend the system with their own abstractions.
Writing aggregate and window functions requires a big mental shift for the programmer. You usually need to define a state variable and provide a set of input/output/accumulator functions and register all that as an aggregate function. This is because of the way this calling convention is meant to be integrated into query plans in a streaming fashion. It's a bit like forcing a programmer to learn some async or co-routine calling convention without offering a simpler synchronous option as a starting point. It's an obstacle.
The application of window or ordered-set aggregate functions also require a lot of verbose syntax to wire up columns or expressions to function inputs and to configure the windows and ordering modes. There isn't really any support to abstract these details away behind the named function, such that the naive user could just call it without knowing how it works internally to solve the whole problem. In other words, having a functional abstraction which can encapsulate data-preconditioning behind an easier interface.
Finally, this approach only addresses the case of reducing a set to a scalar or assigning new scalars for every row in a set. To match the generality of the numpy API would require functions that take sets as input and produce arbitrarily different sets as output. It also needs the host language to allow low-syntax manipulation of intermediate data when composing functions.
So, for full generality, a data transform function might take one set as input and produce another set as output. We would also want things like: set-based function interface typing and function overloading; functions that can setup their own desired traversals of input data including sorting and filtering; functions that can allocate (potentially) large intermediate data using sets or other common data structure idioms; and complementary call-site syntax to easily compose functions with little syntactic boilerplate but also with low marginal syntax overhead to customize and restructure data passed between functions.
It is possible to return arbitrary sets from functions in many systems-- recent versions of the SQL standard even specify table functions (with syntax "RETURNS TABLE(columns)")[0] as well as polymorphic table functions (PTFs)[1]. And in addition to implementations of those standards, extensions like PL/[pg]SQL also have a few other ways of effecting table-like returns (parameter modes, composite type returns).
>function overloading
Not standard, but some systems support it[2].
[0] https://www.postgresql.org/docs/current/xfunc-sql.html#XFUNC...
[1] https://share.ansi.org/Shared%20Documents/News%20and%20Publi...
[2] https://www.postgresql.org/docs/current/xfunc-overload.html
I'd also want to allow a function to be both a table source and a table sink, which I think means that you might need a sub-query like syntax to supply the source that will be consumed by the function. This is a vague idea and not a well-defined language proposal:
CREATE OR REPLACE FUNCTION
-- invent a table-sink func signature?
func1( TABLE t1(a int, b text, c text) )
RETURNS TABLE (x int, y boolean) AS $$
-- access input set via declared name
SELECT
a, b < c
FROM t1
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION
func2( TABLE t1(a int, b boolean) )
RETURNS int AS $$
SELECT a WHERE b
$$ LANGUAGE SQL;
-- implicit positional matching of func input cols?
SELECT f1r.x, f1r.y
FROM func1( SELECT e1, e2, e3 FROM ...) AS f1r;
-- explicit input mapping to override positions?
SELECT f1r.x, f1r.y
FROM func1( SELECT e1, e2, e3 INTO b, a, c FROM ...) AS f1r;
-- function composition
SELECT func2(func1( SELECT e1, e2, e3 FROM ...));It's _every single time_ you need to do this kind of trivial querying you have to write this convoluted mess of SQL.
Many systems support user-defined aggregates[0][1]
[0] https://www.postgresql.org/docs/current/sql-createaggregate....
[1] https://docs.oracle.com/en/database/oracle/oracle-database/2...
It's been an ANSI standard for 36 years.