文档章节

诡异的 unnest 函数

有理想的猪
 有理想的猪
发布于 2015/12/28 17:19
字数 422
阅读 156
收藏 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
博文 91
码字总数 32273
作品 0
红挢
高级程序员
私信 提问
SQL老司机,在SQL中计算 array & map & json数据

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

云雷
06/19
0
0
【r<-模型】使用purrr和broom处理多个模型

整理自《R for data science》 本文介绍3种方法用于处理大量模型。 使用多个简单模型更好地理解复杂数据集。 使用列表列在数据框中保存任意数据结构。 使用broom包将模型转换为整洁数据。 准...

王诗翔
10/16
0
0
正确使用 PostgreSQL 的数组类型

在Heap中,我们依靠PostgreSQL支撑大多数后端繁重的任务,我们存储每个事件为一个hstore blob,我们为每个跟踪的用户维护一个已完成事件的PostgreSQL数组,并将这些事件按时间排序。 Hstore...

oschina
2014/02/26
4K
1
正确使用PostgreSQL的数组类型

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

威武不能笑
2014/09/04
0
0
踩坑CBO,解决那些坑爹的SQL优化问题

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

丁俊
2017/02/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何解决 homebrew 更新慢的问题

之前一直困扰于 Homebrew 的更新速度,曾试过修改更新源(清华、中科大等)的方式,但是并没什么卵用;也试过设置 curl 代理的方式,但是 brew 走的好像不是 curl 的方式,所以也没用。 通过...

whoru
11分钟前
0
0
TiDB EcoSystem Tools 原理解读系列(二)TiDB-Lightning Toolset 介绍

简介 TiDB-Lightning Toolset 是一套快速全量导入 SQL dump 文件到 TiDB 集群的工具集,自 2.1.0 版本起随 TiDB 发布,速度可达到传统执行 SQL 导入方式的至少 3 倍、大约每小时 100 GB,适合...

TiDB
13分钟前
0
0
【Visual Studio 扩展工具】如何在ComponentOneFlexGrid树中显示RadioButton

概述 在ComponentOne Enterprise .NET控件集中,FlexGrid表格控件是用户使用频率最高的控件之一。它是一个功能强大的数据管理工具,轻盈且灵动,以分层的形式展示数据(数据呈现更加直观)。...

葡萄城技术团队
15分钟前
0
0
Maven环境隔离

Maven环境隔离 1. 什么是Maven环境隔离 顾名思义,Maven环境隔离就是将开发中的环境与beat环境、生产环境分隔开,方便进行开发和维护。这个在实际项目中用的还是很多的,如果你的项目用的Mav...

蚂蚁-Declan
15分钟前
1
0
day182-2018-12-19-英语流利阅读-待学习

“性感”时代已去,维密将如何转身? Daniel 2018-12-19 1.今日导读 维多利亚的秘密(Victoria's Secret)这个内衣品牌,最近似乎步入了“中年危机”——曾经打遍天下的“性感”内衣,在主打...

飞鱼说编程
16分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部