Многострочный подвыбор в качестве параметра для `выполнения с использованием` - PullRequest
0 голосов
/ 21 марта 2012

Многолинейный подвыбор будет использоваться в правой части оператора in в предложении where:

create table t (a integer);
insert into t (a) values (1), (9);

drop function if exists f();

create function f()
returns void as $$
begin
execute '
    select a
    from t
    where a in $1
' using (select 1 union select 2);
end;$$
language plpgsql;

select f();

ERROR:  more than one row returned by a subquery used as an expression
CONTEXT:  SQL statement "SELECT (select 1 union select 2)"
PL/pgSQL function "f" line 3 at EXECUTE statement

Как добиться того, что бы вышеприведенная функция работала?

Ответы [ 2 ]

2 голосов
/ 21 марта 2012

Я не вижу в вашем вопросе ничего, что нельзя было бы решить с помощью:

SELECT a
FROM   t
JOIN  (VALUES (1), (2)) x(a) USING (a); -- any query returning multiple int

Можете ли вы прояснить необходимость в вашем примере?


В качестве доказательства концепции это будет проще / быстрее:

CREATE OR REPLACE FUNCTION x.f1()
  RETURNS SETOF integer AS
$BODY$
BEGIN
RETURN QUERY EXECUTE '
    SELECT a
    FROM t
    WHERE a = ANY($1)'
USING ARRAY(VALUES (1), (2)); -- any query here
END;
$BODY$
LANGUAGE plpgsql;

Производительность IN () и = ЛЮБОЙ ()

Ваше наблюдение точно. И этому есть причина. Попробуйте:

EXPLAIN ANALYZE SELECT * FROM tbl WHERE id IN (1,2,3);

План запроса покажет:

Индекс Cond: (id = ANY ('{1,2,3}' :: integer []))

PostgreSQL внутренне преобразует конструкцию id IN (..) в id = ANY(..). Эти двое работают одинаково - за исключением незначительных накладных расходов.

Мой код быстрее строит оператор - точно так, как вы поставили диагноз.

0 голосов
/ 21 марта 2012
create function f()
returns setof integer as $$
begin
return query execute format('
    select a
    from t
    where a in %s
', replace(replace(array(select 1 union select 2)::text, '{', '('), '}', ')'));
end$$
language plpgsql;
...