Function table / Table calculations / Regional revenue z-score

Regional revenue z-score, from Tableau to SQL

Standardizes revenue using the regional mean and sample standard deviation. Below, 8 sample rows go through the calculation and through the SQL, and both return the same numbers.

Calculated field

(SUM([Revenue]) - WINDOW_AVG(SUM([Revenue]))) / WINDOW_STDEV(SUM([Revenue]))

Compute using: addressing Period; partitioning Region

Sample data

RegionPeriodRevenueCost
Harbor112070
Harbor2180100
Harbor3180120
Harbor4240140
Upland19050
Upland2150110
Upland3null90
Upland4330190

The same calculation as SQL

SELECT CAST((("Revenue" - avg("Revenue") OVER (PARTITION BY "Region" ORDER BY "Period" ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) / nullif(stddev_samp("Revenue") OVER (PARTITION BY "Region" ORDER BY "Period" ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),0)) AS DOUBLE) AS result FROM input ORDER BY "Region", "Period"

Runs the example above.

Result

RegionPeriodRevenueCostresult
Harbor112070-1.22474
Harbor21801000
Harbor31801200
Harbor42401401.22474
Upland19050-0.800641
Upland2150110-0.320256
Upland3null90null
Upland43301901.1209

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

Where a naive translation goes wrong

  • An unpartitioned SQL window mixes independent regional calculation sequences.

    Naive SQL

    SELECT CAST((("Revenue" - avg("Revenue") OVER ( ORDER BY "Period" ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) / nullif(stddev_samp("Revenue") OVER ( ORDER BY "Period" ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),0)) AS DOUBLE) AS result FROM input ORDER BY "Region", "Period"
    RegionPeriodRevenueCostresult
    Harbor112070-0.801784
    Harbor2180100-0.0534522
    Harbor3180120-0.0534522
    Harbor42401400.694879
    Upland19050-1.17595
    Upland2150110-0.427618
    Upland3null90null
    Upland43301901.81738

    Matches the calculation

    SELECT CAST((("Revenue" - avg("Revenue") OVER (PARTITION BY "Region" ORDER BY "Period" ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) / nullif(stddev_samp("Revenue") OVER (PARTITION BY "Region" ORDER BY "Period" ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),0)) AS DOUBLE) AS result FROM input ORDER BY "Region", "Period"
    RegionPeriodRevenueCostresult
    Harbor112070-1.22474
    Harbor21801000
    Harbor31801200
    Harbor42401401.22474
    Upland19050-0.800641
    Upland2150110-0.320256
    Upland3null90null
    Upland43301901.1209

Signature

(SUM([Revenue]) - WINDOW_AVG(SUM([Revenue]))) / WINDOW_STDEV(SUM([Revenue]))