HEXBINY: from Tableau to SQL

Returns the vertical coordinate of the nearest hexagonal bin center. Below, 8 sample rows go through the calculation and through the SQL, and both return the same numbers.

Calculated field

HEXBINY([amount], [other])

Sample data

idamountunitsscoreother
1-2.52-0.83
20004
31.530.252
4440.58
5950.811
6166114
7null7null9
848-0.5null

The same calculation as SQL

WITH coords AS (SELECT *,coalesce(amount,0) AS x,coalesce(other,0)/sqrt(3) AS y FROM input), centers AS (SELECT *,3*floor(x/3+0.5) AS ux,floor(y+0.5) AS uy,3*floor((x-1.5)/3+0.5)+1.5 AS sx,floor(y) +0.5 AS sy FROM coords) SELECT CASE WHEN other IS NULL THEN NULL WHEN pow(ux-x,2)+3*pow(uy-y,2)<=pow(sx-x,2)+3*pow(sy-y,2) THEN uy*sqrt(3) ELSE sy*sqrt(3) END AS result FROM centers ORDER BY id

Runs the example above.

Result

idamountunitsscoreresult
1-2.52-0.83.4641
20003.4641
31.530.252.59808
4440.57.79423
5950.810.3923
6166114.7224
7null7null8.66025
848-0.5null

Same rows from the calculation and from the SQL in DuckDB.

Where a naive translation goes wrong

  • Rounding an axis independently does not select the nearest hexagonal center.

    Naive SQL

    SELECT round(other) AS result FROM input ORDER BY id
    idamountunitsscoreresult
    1-2.52-0.83
    20004
    31.530.252
    4440.58
    5950.811
    6166114
    7null7null9
    848-0.5null

    Matches the calculation

    WITH coords AS (SELECT *,coalesce(amount,0) AS x,coalesce(other,0)/sqrt(3) AS y FROM input), centers AS (SELECT *,3*floor(x/3+0.5) AS ux,floor(y+0.5) AS uy,3*floor((x-1.5)/3+0.5)+1.5 AS sx,floor(y) +0.5 AS sy FROM coords) SELECT CASE WHEN other IS NULL THEN NULL WHEN pow(ux-x,2)+3*pow(uy-y,2)<=pow(sx-x,2)+3*pow(sy-y,2) THEN uy*sqrt(3) ELSE sy*sqrt(3) END AS result FROM centers ORDER BY id
    idamountunitsscoreresult
    1-2.52-0.83.4641
    20003.4641
    31.530.252.59808
    4440.57.79423
    5950.810.3923
    6166114.7224
    7null7null8.66025
    848-0.5null

Signature

HEXBINY(number, number)