From 329d9372e02f28f01f387c4154a55cff4a0e797e Mon Sep 17 00:00:00 2001 From: Dharan Aditya Date: Sat, 31 Aug 2024 14:28:07 +0530 Subject: [PATCH 1/8] add boilerplate --- datafusion/functions-aggregate/src/lib.rs | 1 + .../functions-aggregate/src/skewness.rs | 100 ++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 datafusion/functions-aggregate/src/skewness.rs diff --git a/datafusion/functions-aggregate/src/lib.rs b/datafusion/functions-aggregate/src/lib.rs index b54cd181a0cb..459c51636e5e 100644 --- a/datafusion/functions-aggregate/src/lib.rs +++ b/datafusion/functions-aggregate/src/lib.rs @@ -80,6 +80,7 @@ pub mod bool_and_or; pub mod grouping; pub mod nth_value; pub mod string_agg; +mod skewness; use crate::approx_percentile_cont::approx_percentile_cont_udaf; use crate::approx_percentile_cont_with_weight::approx_percentile_cont_with_weight_udaf; diff --git a/datafusion/functions-aggregate/src/skewness.rs b/datafusion/functions-aggregate/src/skewness.rs new file mode 100644 index 000000000000..c886e7eed686 --- /dev/null +++ b/datafusion/functions-aggregate/src/skewness.rs @@ -0,0 +1,100 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::any::Any; +use arrow::array::ArrayRef; +use arrow_schema::DataType; +use datafusion_common::ScalarValue; +use datafusion_expr::{Accumulator, AggregateUDFImpl, Signature, Volatility}; +use datafusion_functions_aggregate_common::accumulator::AccumulatorArgs; + +#[derive(Debug)] +struct SkewnessFunc { + name: String, + signature: Signature +} + +impl SkewnessFunc { + pub fn new() -> Self { + Self { + name: "skewness".to_string(), + signature: Signature::any(1, Volatility::Immutable) + } + } +} + +impl AggregateUDFImpl for SkewnessFunc { + fn as_any(&self) -> &dyn Any { + self + } + + fn name(&self) -> &str { + &self.name + } + + fn signature(&self) -> &Signature { + &self.signature + } + + fn return_type(&self, arg_types: &[DataType]) -> datafusion_common::Result { + Ok(arg_types[0].clone()) + } + + fn accumulator(&self, acc_args: AccumulatorArgs) -> datafusion_common::Result> { + Ok(Box::new(SkewnessAccumulator::new())) + } +} + +#[derive(Debug)] +struct SkewnessAccumulator { + size: usize, + sum: f64, + sum_sqr: f64, + sum_cub: f64 +} + +impl SkewnessAccumulator { + fn new() -> Self { + Self { + size: 0, + sum: 0f64, + sum_sqr: 0f64, + sum_cub: 0f64, + } + } +} + +impl Accumulator for SkewnessAccumulator { + fn update_batch(&mut self, values: &[ArrayRef]) -> datafusion_common::Result<()> { + unimplemented!() + } + fn evaluate(&mut self) -> datafusion_common::Result { + unimplemented!() + } + + fn size(&self) -> usize { + std::mem::size_of_val(self) + } + + fn state(&mut self) -> datafusion_common::Result> { + unimplemented!() + } + + fn merge_batch(&mut self, states: &[ArrayRef]) -> datafusion_common::Result<()> { + unimplemented!() + } +} \ No newline at end of file From 053085fb142f49677dcaea3a8125b9ca3efac821 Mon Sep 17 00:00:00 2001 From: Dharan Aditya Date: Mon, 2 Sep 2024 23:14:49 +0530 Subject: [PATCH 2/8] impl skewness --- datafusion/functions-aggregate/src/lib.rs | 3 +- .../functions-aggregate/src/skewness.rs | 132 +++++++++++++++--- .../tests/cases/roundtrip_logical_plan.rs | 2 + 3 files changed, 117 insertions(+), 20 deletions(-) diff --git a/datafusion/functions-aggregate/src/lib.rs b/datafusion/functions-aggregate/src/lib.rs index 459c51636e5e..993ef604bb15 100644 --- a/datafusion/functions-aggregate/src/lib.rs +++ b/datafusion/functions-aggregate/src/lib.rs @@ -79,8 +79,8 @@ pub mod bit_and_or_xor; pub mod bool_and_or; pub mod grouping; pub mod nth_value; +pub mod skewness; pub mod string_agg; -mod skewness; use crate::approx_percentile_cont::approx_percentile_cont_udaf; use crate::approx_percentile_cont_with_weight::approx_percentile_cont_with_weight_udaf; @@ -170,6 +170,7 @@ pub fn all_default_aggregate_functions() -> Vec> { average::avg_udaf(), grouping::grouping_udaf(), nth_value::nth_value_udaf(), + skewness::skewness_udaf(), ] } diff --git a/datafusion/functions-aggregate/src/skewness.rs b/datafusion/functions-aggregate/src/skewness.rs index c886e7eed686..e0c091b5162c 100644 --- a/datafusion/functions-aggregate/src/skewness.rs +++ b/datafusion/functions-aggregate/src/skewness.rs @@ -15,24 +15,42 @@ // specific language governing permissions and limitations // under the License. -use std::any::Any; -use arrow::array::ArrayRef; -use arrow_schema::DataType; -use datafusion_common::ScalarValue; +use arrow::array::{ArrayRef, AsArray, Float64Array, UInt64Array}; +use arrow::datatypes::Float64Type; +use arrow_schema::{DataType, Field}; +use datafusion_common::{downcast_value, not_impl_err, DataFusionError, ScalarValue}; use datafusion_expr::{Accumulator, AggregateUDFImpl, Signature, Volatility}; -use datafusion_functions_aggregate_common::accumulator::AccumulatorArgs; +use datafusion_functions_aggregate_common::accumulator::{ + AccumulatorArgs, StateFieldsArgs, +}; +use std::any::Any; +use std::ops::{Mul, Sub}; + +make_udaf_expr_and_func!( + SkewnessFunc, + skewness, + x, + "Calculates the excess skewness.", + skewness_udaf +); #[derive(Debug)] struct SkewnessFunc { name: String, - signature: Signature + signature: Signature, +} + +impl Default for SkewnessFunc { + fn default() -> Self { + Self::new() + } } impl SkewnessFunc { pub fn new() -> Self { Self { name: "skewness".to_string(), - signature: Signature::any(1, Volatility::Immutable) + signature: Signature::user_defined(Volatility::Immutable), } } } @@ -41,7 +59,6 @@ impl AggregateUDFImpl for SkewnessFunc { fn as_any(&self) -> &dyn Any { self } - fn name(&self) -> &str { &self.name } @@ -50,27 +67,58 @@ impl AggregateUDFImpl for SkewnessFunc { &self.signature } - fn return_type(&self, arg_types: &[DataType]) -> datafusion_common::Result { - Ok(arg_types[0].clone()) + fn return_type( + &self, + _arg_types: &[DataType], + ) -> datafusion_common::Result { + Ok(DataType::Float64) } - fn accumulator(&self, acc_args: AccumulatorArgs) -> datafusion_common::Result> { + fn accumulator( + &self, + acc_args: AccumulatorArgs, + ) -> datafusion_common::Result> { + if acc_args.is_distinct { + return not_impl_err!("DISTINCT is not implemented for skewness"); + } Ok(Box::new(SkewnessAccumulator::new())) } + + fn state_fields( + &self, + _args: StateFieldsArgs, + ) -> datafusion_common::Result> { + Ok(vec![ + Field::new("count", DataType::UInt64, true), + Field::new("sum", DataType::Float64, true), + Field::new("sum_sqr", DataType::Float64, true), + Field::new("sum_cub", DataType::Float64, true), + ]) + } + + fn coerce_types( + &self, + _arg_types: &[DataType], + ) -> datafusion_common::Result> { + Ok(vec![DataType::Float64]) + } } +/// Accumulator for calculating the excess skewness +/// This implementation follows the [DuckDB implementation] : +/// #[derive(Debug)] struct SkewnessAccumulator { - size: usize, + count: u64, sum: f64, sum_sqr: f64, - sum_cub: f64 + sum_cub: f64, } impl SkewnessAccumulator { fn new() -> Self { Self { - size: 0, + count: 0, sum: 0f64, sum_sqr: 0f64, sum_cub: 0f64, @@ -80,10 +128,36 @@ impl SkewnessAccumulator { impl Accumulator for SkewnessAccumulator { fn update_batch(&mut self, values: &[ArrayRef]) -> datafusion_common::Result<()> { - unimplemented!() + let array = values[0].as_primitive::(); + for val in array.iter().flatten() { + self.count += 1; + self.sum += val; + self.sum_sqr = val.powi(2); + self.sum_cub = val.powi(3); + } + Ok(()) } fn evaluate(&mut self) -> datafusion_common::Result { - unimplemented!() + if self.count <= 2 { + return Ok(ScalarValue::Float64(None)); + } + let count = self.count as f64; + let t1 = 1f64 / self.count as f64; + let mut p = (t1 * (self.sum_sqr - self.sum * self.sum * t1)).powi(3); + if p < 0f64 { + p = 0f64; + } + let div = p.sqrt(); + if div == 0f64 { + return Ok(ScalarValue::Float64(None)); + } + let t2 = (count.mul(count.sub(1f64))) / (count.sub(2f64)); + let res = t2 + * t1 + * (self.sum_cub - 3f64 * self.sum_sqr * self.sum * t1 + + 2f64 * self.sum.powi(3) * t1 * t1) + / div; + Ok(ScalarValue::Float64(Some(res))) } fn size(&self) -> usize { @@ -91,10 +165,30 @@ impl Accumulator for SkewnessAccumulator { } fn state(&mut self) -> datafusion_common::Result> { - unimplemented!() + Ok(vec![ + ScalarValue::from(self.count), + ScalarValue::from(self.sum), + ScalarValue::from(self.sum_sqr), + ScalarValue::from(self.sum_cub), + ]) } fn merge_batch(&mut self, states: &[ArrayRef]) -> datafusion_common::Result<()> { - unimplemented!() + let counts = downcast_value!(states[0], UInt64Array); + let sums = downcast_value!(states[1], Float64Array); + let sum_sqrs = downcast_value!(states[2], Float64Array); + let sum_cubs = downcast_value!(states[3], Float64Array); + + for i in 0..counts.len() { + let c = counts.value(i); + if c == 0 { + continue; + } + self.count += c; + self.sum += sums.value(i); + self.sum_sqr += sum_sqrs.value(i); + self.sum_cub += sum_cubs.value(i); + } + Ok(()) } -} \ No newline at end of file +} diff --git a/datafusion/proto/tests/cases/roundtrip_logical_plan.rs b/datafusion/proto/tests/cases/roundtrip_logical_plan.rs index e174d1b50713..53d9e3de0b3c 100644 --- a/datafusion/proto/tests/cases/roundtrip_logical_plan.rs +++ b/datafusion/proto/tests/cases/roundtrip_logical_plan.rs @@ -72,6 +72,7 @@ use datafusion_functions_aggregate::average::avg_udaf; use datafusion_functions_aggregate::expr_fn::{ approx_distinct, array_agg, avg, bit_and, bit_or, bit_xor, bool_and, bool_or, corr, }; +use datafusion_functions_aggregate::skewness::skewness; use datafusion_functions_aggregate::string_agg::string_agg; use datafusion_proto::bytes::{ logical_plan_from_bytes, logical_plan_from_bytes_with_extension_codec, @@ -903,6 +904,7 @@ async fn roundtrip_expr_api() -> Result<()> { vec![lit(10), lit(20), lit(30)], ), row_number(), + skewness(lit(1.1)), ]; // ensure expressions created with the expr api can be round tripped From 20c922a989988717689f75fb4f054e20ee91c44a Mon Sep 17 00:00:00 2001 From: Dharan Aditya Date: Mon, 2 Sep 2024 23:16:00 +0530 Subject: [PATCH 3/8] docs --- datafusion/functions-aggregate/src/skewness.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datafusion/functions-aggregate/src/skewness.rs b/datafusion/functions-aggregate/src/skewness.rs index e0c091b5162c..81f0cac9f3aa 100644 --- a/datafusion/functions-aggregate/src/skewness.rs +++ b/datafusion/functions-aggregate/src/skewness.rs @@ -30,7 +30,7 @@ make_udaf_expr_and_func!( SkewnessFunc, skewness, x, - "Calculates the excess skewness.", + "The skewness.", skewness_udaf ); @@ -104,7 +104,7 @@ impl AggregateUDFImpl for SkewnessFunc { } } -/// Accumulator for calculating the excess skewness +/// Accumulator for calculating the skewness /// This implementation follows the [DuckDB implementation] : /// #[derive(Debug)] From 20310d731f19fbbceb09c75484658cf0ff50a167 Mon Sep 17 00:00:00 2001 From: Dharan Aditya Date: Mon, 2 Sep 2024 23:38:34 +0530 Subject: [PATCH 4/8] fix acc --- .../functions-aggregate/src/skewness.rs | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/datafusion/functions-aggregate/src/skewness.rs b/datafusion/functions-aggregate/src/skewness.rs index 81f0cac9f3aa..f21db80cb40f 100644 --- a/datafusion/functions-aggregate/src/skewness.rs +++ b/datafusion/functions-aggregate/src/skewness.rs @@ -24,15 +24,9 @@ use datafusion_functions_aggregate_common::accumulator::{ AccumulatorArgs, StateFieldsArgs, }; use std::any::Any; -use std::ops::{Mul, Sub}; +use std::ops::{Div, Mul, Sub}; -make_udaf_expr_and_func!( - SkewnessFunc, - skewness, - x, - "The skewness.", - skewness_udaf -); +make_udaf_expr_and_func!(SkewnessFunc, skewness, x, "The skewness.", skewness_udaf); #[derive(Debug)] struct SkewnessFunc { @@ -132,8 +126,8 @@ impl Accumulator for SkewnessAccumulator { for val in array.iter().flatten() { self.count += 1; self.sum += val; - self.sum_sqr = val.powi(2); - self.sum_cub = val.powi(3); + self.sum_sqr += val.powi(2); + self.sum_cub += val.powi(3); } Ok(()) } @@ -142,16 +136,15 @@ impl Accumulator for SkewnessAccumulator { return Ok(ScalarValue::Float64(None)); } let count = self.count as f64; - let t1 = 1f64 / self.count as f64; - let mut p = (t1 * (self.sum_sqr - self.sum * self.sum * t1)).powi(3); - if p < 0f64 { - p = 0f64; - } + let t1 = 1f64 / count; + let p = (t1 * (self.sum_sqr - self.sum * self.sum * t1)) + .powi(3) + .max(0f64); let div = p.sqrt(); if div == 0f64 { return Ok(ScalarValue::Float64(None)); } - let t2 = (count.mul(count.sub(1f64))) / (count.sub(2f64)); + let t2 = count.mul(count.sub(1f64)).sqrt().div(count.sub(2f64)); let res = t2 * t1 * (self.sum_cub - 3f64 * self.sum_sqr * self.sum * t1 From 40daf18388d164861cb0a77b3c04adddfd3f3566 Mon Sep 17 00:00:00 2001 From: Dharan Aditya Date: Mon, 2 Sep 2024 23:47:27 +0530 Subject: [PATCH 5/8] add docs --- datafusion/functions-aggregate/src/skewness.rs | 7 ++----- docs/source/user-guide/sql/aggregate_functions.md | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/datafusion/functions-aggregate/src/skewness.rs b/datafusion/functions-aggregate/src/skewness.rs index f21db80cb40f..931004934094 100644 --- a/datafusion/functions-aggregate/src/skewness.rs +++ b/datafusion/functions-aggregate/src/skewness.rs @@ -18,7 +18,7 @@ use arrow::array::{ArrayRef, AsArray, Float64Array, UInt64Array}; use arrow::datatypes::Float64Type; use arrow_schema::{DataType, Field}; -use datafusion_common::{downcast_value, not_impl_err, DataFusionError, ScalarValue}; +use datafusion_common::{downcast_value, DataFusionError, ScalarValue}; use datafusion_expr::{Accumulator, AggregateUDFImpl, Signature, Volatility}; use datafusion_functions_aggregate_common::accumulator::{ AccumulatorArgs, StateFieldsArgs, @@ -70,11 +70,8 @@ impl AggregateUDFImpl for SkewnessFunc { fn accumulator( &self, - acc_args: AccumulatorArgs, + _acc_args: AccumulatorArgs, ) -> datafusion_common::Result> { - if acc_args.is_distinct { - return not_impl_err!("DISTINCT is not implemented for skewness"); - } Ok(Box::new(SkewnessAccumulator::new())) } diff --git a/docs/source/user-guide/sql/aggregate_functions.md b/docs/source/user-guide/sql/aggregate_functions.md index edb0e1d0c9f0..c9cd9800ed2b 100644 --- a/docs/source/user-guide/sql/aggregate_functions.md +++ b/docs/source/user-guide/sql/aggregate_functions.md @@ -252,6 +252,7 @@ last_value(expression [ORDER BY expression]) - [regr_sxx](#regr_sxx) - [regr_syy](#regr_syy) - [regr_sxy](#regr_sxy) +- [skewness][#skewness] ### `corr` @@ -527,6 +528,19 @@ regr_sxy(expression_y, expression_x) - **expression_x**: Independent variable. Can be a constant, column, or function, and any combination of arithmetic operators. +### `skewness` + +Computes the skewness value. + +``` +skewness(expression) +``` + +#### Arguments + +- **expression**: Expression to operate on. + Can be a constant, column, or function, and any combination of arithmetic operators. + ## Approximate - [approx_distinct](#approx_distinct) From 0deb487093ca91e91603fb2803b84bc580851cc6 Mon Sep 17 00:00:00 2001 From: Dharan Aditya Date: Mon, 2 Sep 2024 23:47:49 +0530 Subject: [PATCH 6/8] typos --- docs/source/user-guide/sql/aggregate_functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/user-guide/sql/aggregate_functions.md b/docs/source/user-guide/sql/aggregate_functions.md index c9cd9800ed2b..a977636f1361 100644 --- a/docs/source/user-guide/sql/aggregate_functions.md +++ b/docs/source/user-guide/sql/aggregate_functions.md @@ -252,7 +252,7 @@ last_value(expression [ORDER BY expression]) - [regr_sxx](#regr_sxx) - [regr_syy](#regr_syy) - [regr_sxy](#regr_sxy) -- [skewness][#skewness] +- [skewness](#skewness) ### `corr` From 327b03114d3c536f584b385a585d724287f8e88f Mon Sep 17 00:00:00 2001 From: Dharan Aditya Date: Tue, 3 Sep 2024 00:02:42 +0530 Subject: [PATCH 7/8] add some logic tests --- datafusion/functions-aggregate/src/skewness.rs | 14 +++++++------- datafusion/sqllogictest/test_files/aggregate.slt | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/datafusion/functions-aggregate/src/skewness.rs b/datafusion/functions-aggregate/src/skewness.rs index 931004934094..83f915523dd3 100644 --- a/datafusion/functions-aggregate/src/skewness.rs +++ b/datafusion/functions-aggregate/src/skewness.rs @@ -15,10 +15,10 @@ // specific language governing permissions and limitations // under the License. -use arrow::array::{ArrayRef, AsArray, Float64Array, UInt64Array}; -use arrow::datatypes::Float64Type; +use arrow::array::{ArrayRef, AsArray}; +use arrow::datatypes::{Float64Type, UInt64Type}; use arrow_schema::{DataType, Field}; -use datafusion_common::{downcast_value, DataFusionError, ScalarValue}; +use datafusion_common::ScalarValue; use datafusion_expr::{Accumulator, AggregateUDFImpl, Signature, Volatility}; use datafusion_functions_aggregate_common::accumulator::{ AccumulatorArgs, StateFieldsArgs, @@ -164,10 +164,10 @@ impl Accumulator for SkewnessAccumulator { } fn merge_batch(&mut self, states: &[ArrayRef]) -> datafusion_common::Result<()> { - let counts = downcast_value!(states[0], UInt64Array); - let sums = downcast_value!(states[1], Float64Array); - let sum_sqrs = downcast_value!(states[2], Float64Array); - let sum_cubs = downcast_value!(states[3], Float64Array); + let counts = states[0].as_primitive::(); + let sums = states[1].as_primitive::(); + let sum_sqrs = states[2].as_primitive::(); + let sum_cubs = states[3].as_primitive::(); for i in 0..counts.len() { let c = counts.value(i); diff --git a/datafusion/sqllogictest/test_files/aggregate.slt b/datafusion/sqllogictest/test_files/aggregate.slt index 45cb4d4615d7..6ca26b176d91 100644 --- a/datafusion/sqllogictest/test_files/aggregate.slt +++ b/datafusion/sqllogictest/test_files/aggregate.slt @@ -5863,3 +5863,18 @@ ORDER BY k; ---- 1 1.8125 6.8007813 Float16 Float16 2 8.5 8.5 Float16 Float16 + +query R +SELECT skewness(col) FROM VALUES (-10), (-20), (100), (1000), (1000) AS tab(col); +---- +0.574511614753 + +query R +SELECT skewness(DISTINCT col) FROM VALUES (-10), (-20), (100), (1000), (1000) AS tab(col); +---- +1.928752451203 + +query R +SELECT skewness(1.0); +---- +NULL From 7da616e9f7222eab4c6d83c6cebd526615cb8e40 Mon Sep 17 00:00:00 2001 From: Dharan Aditya Date: Tue, 3 Sep 2024 11:30:50 +0530 Subject: [PATCH 8/8] more logic tests --- .../functions-aggregate/src/skewness.rs | 14 ++-- .../sqllogictest/test_files/aggregate.slt | 66 ++++++++++++++++++- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/datafusion/functions-aggregate/src/skewness.rs b/datafusion/functions-aggregate/src/skewness.rs index 83f915523dd3..25bc4c9e7c39 100644 --- a/datafusion/functions-aggregate/src/skewness.rs +++ b/datafusion/functions-aggregate/src/skewness.rs @@ -26,10 +26,16 @@ use datafusion_functions_aggregate_common::accumulator::{ use std::any::Any; use std::ops::{Div, Mul, Sub}; -make_udaf_expr_and_func!(SkewnessFunc, skewness, x, "The skewness.", skewness_udaf); +make_udaf_expr_and_func!( + SkewnessFunc, + skewness, + x, + "Computes the skewness value.", + skewness_udaf +); #[derive(Debug)] -struct SkewnessFunc { +pub struct SkewnessFunc { name: String, signature: Signature, } @@ -96,10 +102,10 @@ impl AggregateUDFImpl for SkewnessFunc { } /// Accumulator for calculating the skewness -/// This implementation follows the [DuckDB implementation] : +/// This implementation follows the DuckDB implementation: /// #[derive(Debug)] -struct SkewnessAccumulator { +pub struct SkewnessAccumulator { count: u64, sum: f64, sum_sqr: f64, diff --git a/datafusion/sqllogictest/test_files/aggregate.slt b/datafusion/sqllogictest/test_files/aggregate.slt index 6ca26b176d91..211e62958693 100644 --- a/datafusion/sqllogictest/test_files/aggregate.slt +++ b/datafusion/sqllogictest/test_files/aggregate.slt @@ -5875,6 +5875,70 @@ SELECT skewness(DISTINCT col) FROM VALUES (-10), (-20), (100), (1000), (1000) AS 1.928752451203 query R -SELECT skewness(1.0); +SELECT skewness(1); ---- NULL + +query R +select skewness(NULL); +---- +NULL + +query error +select skewness(*); + +# out of range +query R +SELECT skewness(DISTINCT col) FROM VALUES (-2e307), (0), (2e307) AS tab(col); +---- +NaN + +statement ok +create table aggr(k int, v decimal(10,2), v2 decimal(10, 2)); + +statement ok +insert into aggr values + (1, 10, null), + (2, 10, 11), + (2, 10, 15), + (2, 10, 18), + (2, 20, 22), + (2, 20, 25), + (2, 25, null), + (2, 30, 35), + (2, 30, 40), + (2, 30, 50), + (2, 30, 51); + +query RRR +select skewness(k), skewness(v), skewness(v2) from aggr; +---- +-3.316624790355 -0.163443669352 0.365400851103 + +query R +select skewness(v2) as sv2 from aggr group by v ORDER BY sv2; +---- +-0.423273160268 +-0.330140951366 +NULL +NULL + +# Window Function +query R +select skewness(v2) over (partition by v) + from aggr order by v; +---- +-0.423273160268 +-0.423273160268 +-0.423273160268 +-0.423273160268 +NULL +NULL +NULL +-0.330140951366 +-0.330140951366 +-0.330140951366 +-0.330140951366 + +statement ok +drop table aggr;