在 PL/pgSQL 中调用另一个函数内部的函数

Posted

技术标签:

【中文标题】在 PL/pgSQL 中调用另一个函数内部的函数【英文标题】:Calling a function inside another function in PL/pgSQL 【发布时间】:2014-02-14 18:10:08 【问题描述】:

我定义了一个函数来总是给我下周日的日期。它工作正常,这是代码:

CREATE FUNCTION nextSunday() RETURNS date AS $$
DECLARE
    dia_semana INT := CAST(EXTRACT(DOW FROM CURRENT_DATE)as INT);
    dia INT :=  7 - dia_semana;
BEGIN
    RETURN current_date + dia;
END;
$$ LANGUAGE plpgsql

我有另一个函数可以将数据转储到文件中,我需要在里面使用nextSunday() 函数:

CREATE OR REPLACE FUNCTION popularTabelaPessoa() RETURNS VOID AS $$
BEGIN
COPY(SELECT pe.id, pe.fk_naturalidade, pe.fk_documentacao_pessoal, pe.nome, 
       pe.cpf, pe.data_nascimento, pe.sexo, pe.estado_civil, pe.nome_mae,
       pe.data_alteracao, pe.usuario_banco_alteracao,
       pe.usuario_aplicacao_alteracao
FROM fluxo_lt.banca ba
INNER JOIN corporativo.localidade lo
    ON ba.fk_municipio = lo.id
INNER JOIN fluxo_lt.agendamento_candidato ac
    ON ac.fk_banca = ba.id
INNER JOIN info_detran.processo as pr
    ON ac.fk_processo = pr.id
INNER JOIN info_detran.candidato as ca
    ON pr.fk_candidato = ca.id
INNER JOIN corporativo.pessoa as pe
    ON ca.fk_pessoa = pe.id
WHERE ba.data = (SELECT nextSunday())
ORDER BY lo.nome, pe.nome)

TO '/tmp/dump.sql';
END;
$$ LANGUAGE plpgsql

但它不起作用。 ba.data字段为date,与nextSunday()函数的返回值类型相同。代码执行没有任何错误,但文件是空白的。如果我硬编码一个日期,它就可以了。已经尝试了所有方法(强制转换、将其放入变量中、作为参数传递给函数),但到目前为止没有任何效果。

我正在使用 Postgres 9.3。

【问题讨论】:

您确定从函数返回的日期与您硬编码的日期相同吗?另外,我在第二段代码中没有看到nextsunday函数,应该在哪里使用? @TomasGreif 是的,该函数正在返回日期类型。你可以测试一下,自己看看。我编辑了问题,现在正在显示 nextSunday() 函数,对此感到抱歉。 我的意思不是类型,而是价值 (2014-02-16)。当您尝试(date_trunc('week', current_date) + interval '1 week' - interval '1 day')::date 而不是(select nextsunday()) 时会发生什么?顺便提一句。我认为您不需要在选择中包装 nextSunday() - ba.data = nextsunday() 也应该工作 - 例如尝试 select 1 where nextsunday() > current_date。如果您添加带有硬编码日期的工作解决方案会很好。 请把你的创建声明ba table. 【参考方案1】:

首先,使用date_trunc(),您的功能可以简单得多:

CREATE FUNCTION next_sunday()
  RETURNS date
  LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT date_trunc('week', LOCALTIMESTAMP)::date + 6;
$func$

PARALLEL SAFE 仅适用于 Postgres 9.6 或更高版本。

如果您必须考虑时区,请参阅:

Ignoring time zones altogether in Rails and PostgreSQL

如果“今天”是星期天,上面将其返回为“下星期天”。 在这种情况下跳过一周:

CREATE FUNCTION next_sunday()
  RETURNS date
  LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT date_trunc('week', LOCALTIMESTAMP + interval '1 day')::date + 6;
$func$;

db小提琴here旧sqlfiddle

或者直接使用date_trunc('week', LOCALTIMESTAMP)::date + 6,而不是函数。

接下来,简化调用:

CREATE OR REPLACE FUNCTION popular_tabela_pessoa()
  RETURNS VOID
  LANGUAGE plpgsql AS
$func$
BEGIN
   COPY (
      SELECT pe.id, pe.fk_naturalidade, pe.fk_documentacao_pessoal, pe.nome
           , pe.cpf, pe.data_nascimento, pe.sexo, pe.estado_civil, pe.nome_mae
           , pe.data_alteracao, pe.usuario_banco_alteracao
           , pe.usuario_aplicacao_alteracao
      FROM   fluxo_lt.banca                 ba
      JOIN   corporativo.localidade         lo ON ba.fk_municipio = lo.id
      JOIN   fluxo_lt.agendamento_candidato ac ON ac.fk_banca = ba.id
      JOIN   info_detran.processo           pr ON ac.fk_processo = pr.id
      JOIN   info_detran.candidato          ca ON pr.fk_candidato = ca.id
      JOIN   corporativo.pessoa             pe ON ca.fk_pessoa = pe.id
      WHERE  ba.data = next_sunday()                                 -- NOT: (SELECT next_sunday())
   -- WHERE  ba.data = date_trunc('week', LOCALTIMESTAMP)::date + 6  -- direct alternative
      ORDER  BY lo.nome, pe.nome)
   TO '/tmp/dump.sql';
END
$func$;

但是,这不能解释您的COPY 失败的原因。您是否确保查询返回任何行?您是否尝试过没有函数包装器的手册COPY

您需要necessary privileges for COPY TO\copy in psql 可能是另一种选择。

【讨论】:

以上是关于在 PL/pgSQL 中调用另一个函数内部的函数的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PL/pgSQL 中创建嵌套函数?

为啥我不能从 pgAdmin pgScript 调用 PL/pgSQL 函数?

如何从 C++ 代码调用 PL/pgSQL 函数

将数组传递给 PostgreSQL PL/pgSQL 函数

PL/pgSQL 函数在 pgAdmin 之外无法正确运行

PL/pgSQL 函数用来自其他属性的所有 NOT NULL 值填充属性