【问题标题】:Stored procedure can not be called due to syntax error由于语法错误,无法调用存储过程
【发布时间】:2020-04-24 04:11:50
【问题描述】:

我们从 SQL Server 迁移到 Postgres,我正在尝试重写存储过程。该过程已正确创建,但我无法调用它。

这是我的程序:

CREATE OR REPLACE PROCEDURE spr_getItems  ( 
  p_kind int = NULL,
  p_customerId varchar(256) = NULL,
  p_resourceIds varchar(2048) = NULL,
  p_referenceIds varchar(2048) = NULL
)
AS $$
BEGIN
  SELECT
    c.kind,
    c.name AS customerName,
    c.oid AS customerId,
    r.name AS resourceName,
    r.oid AS resourceId
    o.fullObject AS fullObjectString
  FROM m_customer c
  JOIN m_resource r
    ON r.oid = c.resourceOid
  LEFT JOIN m_object o
    ON o.customerOid = c.oid
      AND o.customerOid = p_customerId
  WHERE (c.kind = p_kind OR p_kind is NULL)
    AND (c.referenceOid IN (SELECT refTemp.oid FROM tvf_commaSeperatedStringToTable(p_referenceIds) refTemp) OR p_referenceIds is NULL)
    AND (r.oid IN (SELECT resTemp.oid FROM tvf_commaSeperatedStringToTable(p_resourceIds) resTemp) OR p_resourceIds is NULL); 
END;
$$

LANGUAGE 'plpgsql';

表值函数tvf_commaSeperatedStringToTable 只接受一个字符串,将其拆分并返回一个包含所有不同ID 和行号的表。它工作得很好并且经过测试,这里没有错误。

现在当我尝试像这样执行它时

CALL public.spr_getItems (0, null, null, null)

我得到这个输出:

错误:查询没有结果数据的目的地

提示:如果要丢弃 SELECT 的结果,请改用 PERFORM。
上下文:PL/pgSQL 函数 spr_getItems(整数,字符变化,字符变化,字符变化) SQL 语句的第 3 行
SQL 状态:42601

但我不想丢弃结果,我想看到它们。

所以我尝试用 select 调用它

SELECT * 
FROM CALL spr_getItems (0, null, null, null)

然后我得到这个语法错误:

错误:“0”处或附近的语法错误
第 2 行:0,
^
SQL 状态:42601
字符:40

我还尝试以其他几种方式执行它,例如添加“public”。在程序名称之前,但在“.”处出现语法错误。或者只使用select spr_getItems(0, null, null, null)select spr_getItems(0)select * from call spr_getItems (0) 等等。

我是否在做一些完全错误的事情并忽略了文档中的某些内容?

感谢您的帮助!

编辑:澄清我想查看结果
Edit2:不小心复制了错误的函数名
Edit3:按照建议添加了完整的正文

【问题讨论】:

  • @Abelisto 我不想丢弃结果。
  • 到目前为止的两个答案已经为您提供了一些关于如何解决此问题的良好线索,但似乎您也可能正在使用应该使用函数的过程。如果您想从存储的代码中获取结果,请使用函数。 CALL 与过程一起使用。 SELECT 与函数一起使用。
  • @Jeremy 正如我在问题中所说,到目前为止我只使用过 mssql。在那里,我使用存储过程来获取一个或多个可以在前端使用的记录集。我将尝试使用函数而不是过程,看看结果如何。之后我会去postgres中查找函数和存储过程之间的区别,以更好地了解何时使用什么。谢谢
  • @a_horse_with_no_name 添加了程序主体

标签: sql postgresql stored-procedures


【解决方案1】:

这不是 Postgres 的工作方式。过程并不意味着返回结果集。

如果你想使用集合返回函数:

CREATE OR REPLACE function spr_getItems  ( 
  p_kind int = NULL,
  p_customerId varchar(256) = NULL,
  p_resourceIds varchar(2048) = NULL,
  p_referenceIds varchar(2048) = NULL
)
  returns table (kind text, customername text, customerid integer, resourcename text, resourceid integer, fullobjectstring text)
AS $$
  SELECT
    c.kind,
    c.name AS customerName,
    c.oid AS customerId,
    r.name AS resourceName,
    r.oid AS resourceId
    o.fullObject AS fullObjectString
  FROM m_customer c
  JOIN m_resource r
    ON r.oid = c.resourceOid
  LEFT JOIN m_object o
    ON o.customerOid = c.oid
      AND o.customerOid = p_customerId
  WHERE (c.kind = p_kind OR p_kind is NULL)
    AND (c.referenceOid IN (SELECT refTemp.oid FROM tvf_commaSeperatedStringToTable(p_referenceIds) refTemp) OR p_referenceIds is NULL)
    AND (r.oid IN (SELECT resTemp.oid FROM tvf_commaSeperatedStringToTable(p_resourceIds) resTemp) OR p_resourceIds is NULL); 
$$
LANGUAGE sql;

您也不需要 PL/pgSQL 来进行简单的查询封装,language sql 就可以了。

然后像表格一样使用它:

select *
from spr_getitems(....);

请注意,我猜到了 returns table (...) 部分中的数据类型,您必须将其调整为表中使用的真实类型。


您也不需要子选择来处理逗号分隔值。

例如这个:

AND (c.referenceOid IN (SELECT refTemp.oid FROM tvf_commaSeperatedStringToTable(p_referenceIds) refTemp) OR p_referenceIds is NULL)

可以简化为

AND (c.referenceOid = any (string_to_array(p_referenceIds, ',')  OR p_referenceIds is NULL)

但是将多个值作为逗号分隔的字符串传递是一种糟糕的编码风格。您应该将这些参数声明为数组并将适当的数组传递给函数。

【讨论】:

  • 非常感谢,这行得通。但是我想像使用 mssql 库一样在我的节点 js 应用程序中调用该过程。我可以在那里创建一个 ConnectionPool,启动一个请求并提供一些输入参数。然后我只是在程序上运行执行并得到结果。猜想我无论如何都必须交换那个库,但对我来说,调用一个过程似乎比创建选择脚本并运行它们更方便,即使它们非常小。再次,谢谢!找了一篇文章查找postgres中存储过程和函数的区别。
  • 您将不得不更改您的呼叫代码。从函数中选择与从表中选择相同 - 为什么在该库中运行 SELECT 如此“不方便”?不支持运行SELECT语句吗?
  • 此库仅适用于 mssql。我将使用与其类似的 postgres 库(我认为是 pg 或 postgres。还不确定)。两者都支持运行 SELECT 语句。我的意思是我已经能够使用类似的东西:pool.request().input('param1', value1).input('param2', value2).execute('spr_name' (err, result) => { /* do something */ } 在我看来这是非常可读的。使用 pg 库,语法现在类似于pool.query('SELECT * FROM spr_name ($1, $2)', [value1,value2], (err, res) => { /* do something */ })。看起来代码少了一点,但可读性也差了
【解决方案2】:

错误指的是 public.spr_getItems 过程中的函数调用 (spr_getshadowrefs)。也许您正在尝试执行 spr_getshadowrefs 函数而不将结果放入任何变量中。
public.spr_getItems 过程中执行 spr_getshadowrefs 函数时尝试使用 PERFORM。

【讨论】:

  • 他不应该“在执行该函数时使用 PERFORM”,而是在该函数正文的第 3 行使用 PERFORM。
  • "CONTEXT: PL/pgSQL function spr_getshadowrefs(integer,character varying,character varying,character varying) line 3 at SQL statement" 表示发生错误 inside function spr_getshadowrefs ,而不是在调用它时。
  • 哦,你是对的!那么,在 spr_getshadowrefs 函数中是否有一个 SELECT 语句不给任何变量赋值?如果他能给我们提供一些程序代码会很有帮助。
    PD:使用 CALL public.spr_getItems (0, null, null, null)
  • @JuanCarlosYupanquiLozano 抱歉,我不小心复制了一个错误的函数名称,该名称已在另一个查询中打开,但同样的错误。我不在函数内部调用函数。我很糟糕,但感谢您的帮助!
【解决方案3】:

你试过了吗

EXEC spr_getItems p_kind = 0,
  p_customerId = NULL,
  p_resourceIds = NULL,
  p_referenceIds = NULL

【讨论】:

  • 刚刚尝试过... 错误:“EXEC”第 1 行或附近的语法错误:EXEC spr_getItems (0, null, null, null); ^ SQL 状态:42601 字符:1
  • Postgres 中没有exec
猜你喜欢
  • 2018-05-17
  • 2018-05-12
  • 1970-01-01
  • 2011-04-18
  • 2012-04-12
  • 2014-07-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多