A python analysis package for building SQL expressions.
Project description
polymeasure
A python analysis package for building SQL expressions
A PolyMeasure (or measure) represents a SQL "group by one view, evaluate over another" statement, with options for supplying the usual SQL operators or modifying the evaluation in other programmatic ways. The class provides a framework for creating analysis expressions over SQL database systems, in particular the duckdb SQL engine.
PolyMeasures have three main components
- an inner view, also a PolyMeasure
- a set of outer PolyMeasures to evaluate over that view, and
- a set of dimensions to group the inner view by when evaluating the outer view(s).
The function evaluate() returns a SQL statement, built recursively from those components.
In the documentation we drop the name parameter and write
M( Outer * Dim; Inner: Where, Context )
when describing a PolyMeasure, in line with the order of the other parameters of importance.
How it works in a nutshell
In pseudo-sql, M( Inner * Dim; Outer; Where, Context ) evaluates as:
with __VIEW__ as ( [select [Inner] from view([Inner])] )
select [(
select [Outer] from (view(Outer) OR __VIEW__) dynamic_view
where dynamic_view.dim(Outer) = __VIEW__.dim(Outer)
)], Dim
from __VIEW__
where Where
group by Dim
<<context>>
There is a simpler presentation when Dim = Rowset(G):
with __VIEW__ as ( [select [Inner] from view([Inner])] )
select [Outer], __VIEW__.G
from __VIEW__
where Where
<<context>>
How it works
The context can be parameters like having or order by clauses. The where parameter specifies additional filters to apply to the
There are two classes of PolyMeasures - those with a free view, where Outer = None, or a bound view
which already exists in the database.
A bound measure with the usual arguments will be denoted B( Inner * Dim; Outer: Where )
and a free measure denoted F( Inner * Dim; Outer: Where ). Free views become handy expressions like
"count() of any inner table" or "count() over dimensions of the inner table".
Free measures take on the context of the inner query in a PolyMeasure, rather than referencing a basic view in the schema. This allows a single PolyMeasure object to perform a double aggregation over a given view, where we group once, then group the resulting rowset again and perform some aggregation.
If a free measure is supplied to the outer measure list, it will query the corresponding inner measure list. Free measures should not be supplied as the inner measure of a PolyMeasure, unless the outer measures can supply their own inner bindings.
Bound measures should have a default string value for the view, appropriate to the schema. Using the supplied factory method BoundedMeasure will return a super-classed PolyMeasure keyed to a specific view, for convenience.
In the following examples, we assume one unique bounded measure exists, B = B(dim=Rowset(), inner=main_view), which acts as the ultimate "leaf" measure. The class Free is also provided, which defaults the measure view to Free instead, and is aliased F.
The Outer and Inner arguments are PolyMeasure vectors, which each can return tables of any dimension. When different dimensions are supplied in the outer measures, self.dim is used to group the inner view, but each measure still evaluates by matching only on its own dimension, if specified. No attempt is made to reconcile the dimensions between inner and outer arguments - if a measure requests a column that doesn't exist in dim(M) (the inner dimension specified by M), then the SQL parser will let you know :)
When supplied as an argument, a tuple is interpreted as a "Dummy PolyMeasure" (name, inner, [dim]), where dim can be omitted. These measures are always free.
When defining dimensions, [] means group by the whole table, RowSet means do not group the view. None is a wildcard, which means the measure will default to the dimensions of the enclosing measure after dimension promotion.
The view and where parameters are applied to the inner query, Inner * Dim. For example if you want to apply a filter context to Outer directly (which is the final output aggregation), use M( Inner * Dim; F(Outer: Where_Outer): View, Where)
==========================================
Invalid measures fail on evaluation, not instantiation. Test with where 0 = 1 to validate.....
==========================================
Bound measures are "inner idempotent", meaning passing them as the sole argument to an inner parameter of a PolyMeasure constructor creates an object with the same evaluate() properties.
Free measures don't have this property. The free context of F is overwritten by the context of the nearest enclosing bound measure B.
In summary:
B( B( Outer * Dim; Inner: Where) )
= F( B( Outer * Dim; Inner: Where) )
= B( F( Outer * Dim; Inner: Where) )
= B( Outer * Dim; Inner: Where)
all hold. (Note: Inner=None implicitly in the expression F( Outer * Dim; Inner: Where))
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file polymeasure-0.1.1.tar.gz.
File metadata
- Download URL: polymeasure-0.1.1.tar.gz
- Upload date:
- Size: 15.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e6478a3501c0848f4899603f33fb71c0e9b72ba8b022adb7240631f8338a331
|
|
| MD5 |
6b15a897d6f1f2860faf3814d4a739cc
|
|
| BLAKE2b-256 |
5ee4339ffa020975afce578d1ac63fbd1dd0af9111d1639390c29ccbc37f17a9
|
File details
Details for the file polymeasure-0.1.1-py3-none-any.whl.
File metadata
- Download URL: polymeasure-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdf7a36899d46615afafc00f5e0af355abc37d96f642426a93b1e43886e84643
|
|
| MD5 |
294bb36d3cf78d0afd25b69051c9d63f
|
|
| BLAKE2b-256 |
f665a48f5424e09a86254570b1af00a12be1cf04775ed3b5d36c9fa51c9de0da
|