文档章节

诡异的 unnest 函数

有理想的猪
 有理想的猪
发布于 2015/12/28 17:19
字数 422
阅读 125
收藏 0

发现函数 unnest 定义如下:

CREATE OR REPLACE FUNCTION unnest(anyarray)
  RETURNS SETOF anyelement AS
'array_unnest'
  LANGUAGE internal IMMUTABLE STRICT
  COST 1
  ROWS 100;

为了可读性,这是还原后的SQL 语句,实际上它是在 pg_proc.h 中定义的:

DATA(insert OID = 2331 (  unnest		   PGNSP PGUID 12 1 100 0 0 f f f f t t i 1 0 2283 "2277" _null_ _null_ _null_ _null_ array_unnest _null_ _null_ _null_ ));

运行一下:

postgres=# select unnest(array[10,20]);
 unnest 
--------
     10
     20
(2 rows)

postgres=#

很正常是吧,换种方式:

postgres=# SELECT unnest(array[10,20],array['foo','bar'],array[1.0]);
ERROR:  function unnest(integer[], text[], numeric[]) does not exist
LINE 1: SELECT unnest(array[10,20],array['foo','bar'],array[1.0]);
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
postgres=#

这也正常对吧,只支持一个参数嘛,再换种方式:

postgres=# SELECT * FROM unnest(array[10,20],array['foo','bar'],array[1.0]);
 unnest | unnest | unnest 
--------+--------+--------
     10 | foo    |    1.0
     20 | bar    |       
(2 rows)

postgres=#

发生了什么事?

代码(parse_clause.c)在这里:

if (IsA(fexpr, FuncCall))
{
	FuncCall   *fc = (FuncCall *) fexpr;

	if (list_length(fc->funcname) == 1 &&
		strcmp(strVal(linitial(fc->funcname)), "unnest") == 0 &&
		list_length(fc->args) > 1 &&
		fc->agg_order == NIL &&
		fc->agg_filter == NULL &&
		!fc->agg_star &&
		!fc->agg_distinct &&
		!fc->func_variadic &&
		fc->over == NULL &&
		coldeflist == NIL)
	{
		ListCell   *lc;

		foreach(lc, fc->args)
		{
			Node	   *arg = (Node *) lfirst(lc);
			FuncCall   *newfc;

			newfc = makeFuncCall(SystemFuncName("unnest"),
								 list_make1(arg),
								 fc->location);
... // 更多

在 FROM 子句里边的函数调用叫做 RangeFunction,而只有这个 unnest 做了特殊处理,实际上三个参数函数被调用了三次。

如果我们有类似处理需求,这是一个可以参考的手段。

语法引擎(gram.y)代码如下:

from_list:
	table_ref						{ $$ = list_make1($1); }
	| from_list ',' table_ref				{ $$ = lappend($1, $3); }
		;

/*
 * table_ref is where an alias clause can be attached.
 */
table_ref:	relation_expr opt_alias_clause
... // 省略
			| func_table func_alias_clause
				{
					RangeFunction *n = (RangeFunction *) $1;
					n->alias = linitial($2);
					n->coldeflist = lsecond($2);
					$$ = (Node *) n;
				}


By, PostgreSQL中国用户会,http://postgres.cn

© 著作权归作者所有

共有 人打赏支持
有理想的猪
粉丝 136
博文 87
码字总数 30090
作品 0
红挢
高级程序员
SQL老司机,在SQL中计算 array & map & json数据

场景 通常,我们处理数据,一列数据类型要么是字符串,要么是数字,这些都是primitive类型的数据。在某些比较复杂的业务场景下,我们会在一列中使用复杂的格式,例如数组array, 对象(map),j...

云雷
06/19
0
0
正确使用PostgreSQL的数组类型

2014-03-03 10:10 佚名 开源中国编译 我要评论(0) 字号:T | T 在Heap中,我们依靠PostgreSQL支撑大多数后端繁重的任务,我们存储每个事件为一个hstore blob,我们为每个跟踪的用户维护一个已...

威武不能笑
2014/09/04
0
0
jOOQ 1.6.4 发布,Java的ORM框架

jOOQ 高效的合并了复杂SQL、类型安全、源码生成、Active Records、存储过程以及高级数据类型的 Java 类库。 示例代码: // Create a new record and insert it into the databaseTBookRecor...

红薯
2011/08/08
643
3
踩坑CBO,解决那些坑爹的SQL优化问题

本文根据DBAplus社群第93期线上分享整理而成。 本次分享大纲: CBO( Cost Based Optimizer)优化器是目前Oracle广泛使用的优化器,其使用统计信息、查询转换等计算各种可能的访问路径成本,并...

丁俊
2017/02/27
0
0
c++的诡异与艺术一例

c++到底是诡异的还是艺术的,可能都是吧,说它诡异是因为没有理解它的精髓,说它艺术那是因为理解了它的精髓,我这里仅以一个实际的例子说明,在工作过程中,我的项目经理让我看一段程序,可...

晨曦之光
2012/04/10
27
0

没有更多内容

加载失败,请刷新页面

加载更多

关于pip

我在更新pip的时候碰到的一些问题。 第一次安装,直接安装就ok了,所以也没研究,没想到后来由于安装了python2.x和python3.x之后出现了问题。 如果要将pip更新到最新版本需要指明是哪个版本的...

恰东
29分钟前
1
0
对硬盘进行分区时,GPT和MBR有什么区别

在Windows 8或8.1中设置新磁盘时,系统会询问你是想要使用MBR还是GPT分区。GPT是一种新的标准,并在逐渐取代MBR。 GPT带来了很多新特性,但MBR仍然拥有最好的兼容性。GPT并不是Windows专用的...

yizhichao
31分钟前
2
0
区块链教程btcpool矿池源码分析StratumServer模块解析

兄弟连区块链教程btcpool矿池源码分析StratumServer模块解析 核心机制总结 接收的job延迟超过60秒将丢弃 如果job中prevHash与本地job中prevHash不同,即为已产生新块,job中isClean状态将置为...

兄弟连区块链入门教程
32分钟前
1
0
JS中的异常捕获

JS中的异常捕获(目的:把抛出的错误捕获到,不让其阻断浏览器的继续执行) try{//需要执行的JS代码(可能会报错)}catch(e){//try中代码报错,会执行catch}finally{//不管try中的代...

NDweb
42分钟前
2
0
ObjectARX_AcDb2dPolyline复杂实体

1遍历:访问或者编辑复杂实体也需要通过特定的方式。 AcDb2dPolyline的顶点信息不能通过AcDb2dPolyline对象直接得到,需要遍历AcDb2dPolyline所包含的AcDb2dVertex对象: void IteratePolylin...

一个小妞
44分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部