Calculated field
(SUM([Revenue]) - WINDOW_AVG(SUM([Revenue]))) / WINDOW_STDEV(SUM([Revenue]))
Compute using: addressing Period; partitioning Region
Sample data
| Region | Period | Revenue | Cost |
|---|---|---|---|
| Harbor | 1 | 120 | 70 |
| Harbor | 2 | 180 | 100 |
| Harbor | 3 | 180 | 120 |
| Harbor | 4 | 240 | 140 |
| Upland | 1 | 90 | 50 |
| Upland | 2 | 150 | 110 |
| Upland | 3 | null | 90 |
| Upland | 4 | 330 | 190 |
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.
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"Written for this dialect; not run here.
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 FLOAT64) AS result FROM input ORDER BY `Region`, `Period`
Written for this dialect; not run here.
Result
| Region | Period | Revenue | Cost | result |
|---|---|---|---|---|
| Harbor | 1 | 120 | 70 | -1.22474 |
| Harbor | 2 | 180 | 100 | 0 |
| Harbor | 3 | 180 | 120 | 0 |
| Harbor | 4 | 240 | 140 | 1.22474 |
| Upland | 1 | 90 | 50 | -0.800641 |
| Upland | 2 | 150 | 110 | -0.320256 |
| Upland | 3 | null | 90 | null |
| Upland | 4 | 330 | 190 | 1.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"Region Period Revenue Cost result Harbor 1 120 70 -0.801784 Harbor 2 180 100 -0.0534522 Harbor 3 180 120 -0.0534522 Harbor 4 240 140 0.694879 Upland 1 90 50 -1.17595 Upland 2 150 110 -0.427618 Upland 3 null 90 null Upland 4 330 190 1.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"Region Period Revenue Cost result Harbor 1 120 70 -1.22474 Harbor 2 180 100 0 Harbor 3 180 120 0 Harbor 4 240 140 1.22474 Upland 1 90 50 -0.800641 Upland 2 150 110 -0.320256 Upland 3 null 90 null Upland 4 330 190 1.1209
Signature
(SUM([Revenue]) - WINDOW_AVG(SUM([Revenue]))) / WINDOW_STDEV(SUM([Revenue]))