Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

polymeasure-0.1.1.tar.gz (15.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

polymeasure-0.1.1-py3-none-any.whl (14.9 kB view details)

Uploaded Python 3

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

Hashes for polymeasure-0.1.1.tar.gz
Algorithm Hash digest
SHA256 8e6478a3501c0848f4899603f33fb71c0e9b72ba8b022adb7240631f8338a331
MD5 6b15a897d6f1f2860faf3814d4a739cc
BLAKE2b-256 5ee4339ffa020975afce578d1ac63fbd1dd0af9111d1639390c29ccbc37f17a9

See more details on using hashes here.

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

Hashes for polymeasure-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bdf7a36899d46615afafc00f5e0af355abc37d96f642426a93b1e43886e84643
MD5 294bb36d3cf78d0afd25b69051c9d63f
BLAKE2b-256 f665a48f5424e09a86254570b1af00a12be1cf04775ed3b5d36c9fa51c9de0da

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page