前文再续,书接上一回。
上一节我们简单说了利用SetOfIterator返回一个srf(Set Returning Functions),但是很多情况下,一个单值序列并不能很好的满足我们的需求,所以今天我们来说另外一个作用更广泛的srf:
TableIterator
顾名思义,SetOfInterator返回的是一个Set,那么TableIterator返回的自然是一个表格了,下面先来看一个例子:
代码如下:(具体说明后面再说)
#[pg_extern]
fn get_values() ->
TableIterator<'static, (name!(index, i32), name!(value, f64))> {
let v:Vec<(i32,f64)> = vec![
(1,0.5),
(2,0.33),
(3,0.15),
(4,0.35)
];
TableIterator::new(v)
}
效果如下:
有同学说,虾神,你出来的这个内容,不是表格啊,每行怎么都是一个tuple呢?
别急,我们换一个写法:
对比一下我们的接口,就很明显了,我们在函数里面定义的返回类型,正好对应生成的表格中的字段,而TabletIterator里面的值,就正好对应了生成的表格里面的值:
下面我们来简单解析TabletIterator这个返回类型的代码:
/**
语法:
TableIterator<'生命周期标识,
(
name!(字段名1, 字段类型1),
name!(字段名2, 字段类型2),
name!(字段名n, 字段类型n),……
)
>
其中,name!是Rust的定义的宏,里面的参数一个是tuple,用于声明返回值的结构,尤其是返回值为表迭代器的函数中提供 SQL 名称。
*/
//示例:
TableIterator<'static,
(
name!(id, i64),
name!(dept_code, String),
name!(full_text, &'static str)
)
然后看看这个结构的构造方式:
//首先构造一个集合,集合内部的结构与定义的结构一样:
let v:Vec<(i32,f64)> = vec![
(1,0.5),
(2,0.33),
(3,0.15),
(4,0.35)
];
//然后把处理好的集合,直接构造为TableIterator结构即可。
TableIterator::new(v)
下面我们在来看一个例子,比如按照你需要的数量,来生成一个随机填充的表格,代码如下:
#[pg_extern]
fn random_values(num_rows: i32) ->
TableIterator<'static, (name!(index, i32), name!(value, f64))> {
TableIterator::new((1..=num_rows).map(|i| (i, rand::random::<f64>())))
}
效果如下:
使用SQL的方式来生成表格:
这个表格是可以完整使用SQL进行计算分析的,比如,生成100条随机数据,value大于0.95的,只有5条……很明显这个随机函数是正态分布的……:
好了,下面我们来看一个小案例:
返回一个序列的功能在实际工作中是经常用的,特别是做数据分析的同学,因为很多分析的结果不可能只有一条记录。
例如有些不追求数据库范式的设计,可能把数据存储成这个样子:
例如,其中values每天的平均空气质量(随机模拟数据,不要在意这些细节)
然后需求就是要对数组型字段进行计算……
当然,postgresql在9.6之后就支持json和array了,例如array可以通过ANY进行查询,也可以unnest函数进行展开:
例如我们要求2015年8月每个站点的最大值:
先要用UNNEST函数,把整个数组展开,然后再进行groupby。
但是现在问题来了,因为每个月的数据是按每天来计算的,我现在想知道,每个月,哪一天的数值最高?
要说找最高的,还是比较容易的,但是要找这是哪一天,就不太容易了,需要先求max,然后再求下标:
(叠甲:虾神对SQL不是特别熟,所以SQL代码写起来估计效率会很差,大家将就看看就是,不过:
)
效果如下:
那么我们如果要在pgrx里面来做这个功能,怎么做呢?相对来说就非常简单了,代码如下:
#[pg_extern]
fn get_max_value(value:Vec<i32>) ->
TableIterator<
'static, (name!(day,i32),name!(maxvalue,i32))
>{
let mut idx = 0;
let mut max = 0;
//求max的值和数组的下标
for i in 0..value.len(){
if max < value[i]{
max = value[i];
idx = i;
}
}
//下标+1是因为pg的数组是从1开始的,另外我们求的是日期,也是从1开始
TableIterator::new(vec![(idx as i32 + 1,max)])
}
效果如下:
用表格数据测试一下:
真是太残暴了……
打完收工