Skip to main content

A python analysis package for SQL data modelling.

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. Filtering clauses like where and having can be supplied as arguments to the PolyMeasure or evaluate() call. Where clauses are abstract python FilterExpression objects that can be given dynamic behaviours depending on evaluation context.

In this 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

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 row set 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 bound_objects will return a super-classed PolyMeasure and FilterExpression objects 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, outer, [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 at all. None is a wildcard, which means the measure will default to the dimensions of the enclosing measure after dimension promotion. None and [] will behave identically in most cases.

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.3.tar.gz (18.5 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.3-py3-none-any.whl (16.9 kB view details)

Uploaded Python 3

File details

Details for the file polymeasure-0.1.3.tar.gz.

File metadata

  • Download URL: polymeasure-0.1.3.tar.gz
  • Upload date:
  • Size: 18.5 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.3.tar.gz
Algorithm Hash digest
SHA256 198dbc7ae060eee814df969de8731a80436d3c4686a4c5dbe24932d613ea7793
MD5 3943feb43f863c4ec29be6e160c3e796
BLAKE2b-256 14afa7d7049130be24ac5b97848609647d45f2273ad2f2d9edbf0c77999fb456

See more details on using hashes here.

File details

Details for the file polymeasure-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: polymeasure-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 16.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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 128acb255524e2700c438b93918258ea85f0bc08c22df2a213bfbbf52b7a3d94
MD5 5dceca5bc8f7d58056c948074d2665ba
BLAKE2b-256 ec4a39c63937142a69b984de1170e7fc91dbac3464c5b5f83aa429c30953d9d8

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