PostgreSQL: 关于 VARIADIC 函数

PostgreSQL 8.4及以上版,新增特性中包括支持 VARIADIC 函数, 是指函数支持不定数量的参数,只要靠后的参数的数据类型(除数组外)一致即可识别。在函数内部,这些一致类型的参数,会被当作一个数组来处理。但如果其中有一个类型和前后不一致,就无法支持。

这个特性可以让处理集合类的参数变得更灵活。

应用实例:商品表和标签(Tag)的多对多关系。存储过程如下:



CREATE OR REPLACE FUNCTION goods_tag_add(a_goods_id int, VARIADIC a_tags text[], OUT t_id INT8) 
RETURNS SETOF INT8 AS $$
DECLARE
	t_rec record;
	i int4;
BEGIN
	FOR i IN SELECT generate_subscripts(a_tags, 1) LOOP
		-- RAISE NOTICE 'tag: %', a_tags[i]; // debug
		
		SELECT id FROM goods_tag WHERE name = a_tags[i] INTO t_rec;
		IF FOUND THEN
			t_id := t_rec.id;
		ELSE
			INSERT INTO goods_tag(name)
			VALUES (a_tags[i]);
			t_id := CURRVAL('goods_tag_id_seq');
		END IF;
		
		IF NOT EXISTS(SELECT created FROM goods_tag_map 
			WHERE goods_id = a_goods_id AND tag_id = t_id) THEN
			INSERT INTO goods_tag_map(goods_id, tag_id)
			VALUES(a_goods_id, t_id);
		END IF;
		
		RETURN NEXT;

	END LOOP;

	RETURN;
	
END;
$$ LANGUAGE 'plpgsql';

调用此函数的PHP代码示例:


$goods_id = 1; // 目标(这里以商品为例)ID,整数类型
$tags = array('上衣', '夏季', '休闲'); // 不定数量的 tag 文字
$tag_ids = Da_Wrapper::getAll(DB_NS, 
		"SELECT goods_tag_add(?,".implode(',',str_split(str_repeat('?', count($tags)))).")", 
		array_merge(array($goods_id),$tags));
// Da_Wrapper 类是对PDO的封装,DB_NS 是连接串定义,SQL语句之所以这样写是不管 $tags元素有多少,都可以拼成参数传给存储过程

* PostgreSQL 约定了 函数参数最多为100个,如果确实超过这个数,可以分拆成多次调用。不过,多数应用里应该没这么多吧。

参考:
What is new in PostgreSQL 8.4
Waiting for 8.4 – variadic functions
在PostgreSQL中模拟MySQL的ORDER BY FIELD()


Comments are closed.