我正在编写一个迭代数组的多态 PL / pgSQL函数。我对使用FOREACH
感兴趣,但我无法弄清楚如何使用正确的类型声明临时变量。
我的功能如下,有关详细信息,请参阅第4行的评论。
CREATE OR REPLACE FUNCTION uniq(ary anyarray) RETURNS anyarray AS $$
DECLARE
ret ary%TYPE := '{}';
v ???; -- how do I get the element type of @ary@?
BEGIN
IF ary IS NULL THEN
return NULL;
END IF;
FOREACH v IN ARRAY ary LOOP
IF NOT v = any(ret) THEN
ret = array_append(ret, v);
END IF;
END LOOP;
RETURN ret;
END;
$$ LANGUAGE plpgsql;
答案 0 :(得分:3)
AFAIK,你不能声明多态类型的变量而不用 a"模板"变量或参数。
本章末Declaring Function Parameters的手册中有相关示例,但 此技巧未涵盖:添加另一个IN
函数定义的数据类型为INOUT
的{{1}}或OUT
参数。它自动解析为匹配元素类型,可以(ab)直接在函数体内用作变量,也可以用作更多变量的模板:
ANYELEMENT
相关:
复制类似的类型仅适用于CREATE OR REPLACE FUNCTION uniq1(ary ANYARRAY, v ANYELEMENT = NULL)
RETURNS anyarray AS
$func$
DECLARE
ret ary%TYPE := '{}';
some_var v%TYPE; -- we could declare more variables now
-- but we don't need to
BEGIN
IF ary IS NULL THEN
RETURN NULL;
END IF;
FOREACH v IN ARRAY ary LOOP -- instead, we can use v directly
IF NOT v = any(ret) THEN
ret := array_append(ret, v);
END IF;
END LOOP;
RETURN ret;
END
$func$ LANGUAGE plpgsql;
部分,并且是不同的类型转换。 It is explained in the manual here.
指定默认值,因此添加的参数不必包含在函数调用中:DECLARE
ANYELEMENT
致电(未更改):
= NULL
为了方便,我实际上会使用OUT参数并反转测试逻辑:
SELECT uniq1('{1,2,1}'::int[]);
SELECT uniq1('{foo,bar,bar}'::text[]);
但是这仍然不包括所有包含NULL元素的情况。
也适用于NULL元素:
CREATE OR REPLACE FUNCTION uniq2(ary ANYARRAY, elem ANYELEMENT = NULL
, OUT ret ANYARRAY)
RETURNS anyarray AS
$func$
BEGIN
IF ary IS NULL
THEN RETURN;
ELSE ret := '{}'; -- init
END IF;
FOREACH elem IN ARRAY ary LOOP
IF elem = ANY(ret) THEN -- do nothing
ELSE
ret := array_append(ret, elem);
END IF;
END LOOP;
END
$func$ LANGUAGE plpgsql;
检查数组中的NULL有点痛苦:
所有这些功能都是只是概念验证。我会使用 。代替:
在Postgres 9.4中使用CREATE OR REPLACE FUNCTION uniq3(ary ANYARRAY, elem ANYELEMENT = NULL
, OUT ret ANYARRAY)
RETURNS anyarray AS
$func$
BEGIN
IF ary IS NULL
THEN RETURN;
ELSE ret := '{}'; -- init
END IF;
FOREACH elem IN ARRAY ary LOOP
IF elem IS NULL THEN -- special test for NULL
IF array_length(array_remove(ret, NULL), 1) = array_length(ret, 1) THEN
ret := array_append(ret, NULL);
END IF;
ELSIF elem = ANY(ret) THEN -- do nothing
ELSE
ret := array_append(ret, elem);
END IF;
END LOOP;
END
$func$ LANGUAGE plpgsql;
来保留元素的原始顺序。
详细解释:
单值基本代码:
WITH ORDINALITY
返回:
SELECT ARRAY (
SELECT elem
FROM (
SELECT DISTINCT ON (elem) elem, i
FROM unnest('{1,2,1,NULL,4,NULL}'::int[]) WITH ORDINALITY u(elem, i)
ORDER BY elem, i
) sub
ORDER BY i) AS uniq;
关于uniq
------------
{1,2,NULL,4}
:
内置于查询中:
DISTINCT ON
这有一个小角落的情况:它返回一个空数组一个NULL数组。涵盖所有基础:
SELECT *
FROM test t
, LATERAL (
SELECT ARRAY (
SELECT elem
FROM (
SELECT DISTINCT ON (elem) elem, i
FROM unnest(t.arr) WITH ORDINALITY u(elem, i)
ORDER BY elem, i
) sub
ORDER BY i) AS arr
) a;
或者:
SELECT t.*, CASE WHEN t.arr IS NULL THEN NULL ELSE a.arr END AS arr
FROM test t
, LATERAL (
SELECT ARRAY (
SELECT elem
FROM (
SELECT DISTINCT ON (elem) elem, ord
FROM unnest(t.arr) WITH ORDINALITY u(elem, ord)
ORDER BY elem, ord
) sub
ORDER BY ord) AS arr
) a;
在 Postgres 9.3 或更早版本中,您可以使用SELECT *
FROM test t
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT elem
FROM (
SELECT DISTINCT ON (elem) elem, i
FROM unnest(t.arr) WITH ORDINALITY u(elem, i)
ORDER BY elem, i
) sub
ORDER BY i) AS arr
) a ON t.arr IS NOT NULL;
代替:
generate_subscripts()
我们在sqlfiddle中需要这个,目前只支持第9.3页,所以SELECT *
FROM test t
, LATERAL (
SELECT ARRAY (
SELECT elem
FROM (
SELECT DISTINCT ON (t.arr[i]) t.arr[i] AS elem, i
FROM generate_subscripts(t.arr, 1) i
ORDER BY t.arr[i], i
) sub
ORDER BY i
) AS arr
) a;
不可用:
答案 1 :(得分:2)
我不知道如何声明`@section('scripts')`
<script>
$(function() {
$("#posts-table").DataTable({
order: [[0, "desc"]]
});
});
</script>
`@stop`
参数的基类型变量(the documentation没有提到这种可能性。)
您可以使用anyarray
代替整数变量:
FOR LOOP
但是,循环和变量可能没有必要:
CREATE OR REPLACE FUNCTION uniq(ary anyarray) RETURNS anyarray AS $$
DECLARE
ret ary%TYPE := '{}';
i int;
BEGIN
IF ary IS NULL THEN
return NULL;
END IF;
FOR i IN array_lower(ary, 1) .. array_upper(ary, 1) LOOP
IF NOT ary[i] = any(ret) THEN
ret = array_append(ret, ary[i]);
END IF;
END LOOP;
RETURN ret;
END;
$$ LANGUAGE plpgsql;
使数组顺序保持不变的上述函数的版本:
create or replace function uniq_without_loop(arr anyarray)
returns anyarray language plpgsql as $$
begin
return (
select array_agg(distinct elem)
from unnest(arr) elem);
end $$;