英文:
Stored procedure can not be called due to syntax error
问题
我们已经从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_commaSeparatedStringToTable(p_referenceIds) refTemp) OR p_referenceIds is NULL)
AND (r.oid IN (SELECT resTemp.oid FROM tvf_commaSeparatedStringToTable(p_resourceIds) resTemp) OR p_resourceIds is NULL);
END;
$$
LANGUAGE 'plpgsql';
表值函数 tvf_commaSeparatedStringToTable
仅接受一个字符串,将其拆分并返回包含所有不同ID和行号的表。它运行正常并已经测试,没有错误。
现在,当我尝试像这样执行它时:
CALL public.spr_getItems (0, null, null, null)
我会得到以下输出:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function spr_getItems(integer,character varying,character varying,character varying) line 3 at SQL statement
SQL state: 42601
但我不想丢弃结果,我想看到它们。
所以我尝试使用SELECT
调用它:
SELECT *
FROM CALL spr_getItems (0, null, null, null)
然后我得到以下语法错误:
ERROR: syntax error at or near "0"
LINE 2: 0,
^
SQL state: 42601
Character: 40
我还尝试了几种其他方法,例如在存储过程名称之前添加 "public.",但然后会出现语法错误,指的是 "."。或者只是使用 select spr_getItems(0, null, null, null)
或 select spr_getItems(0)
,select * from call spr_getItems (0)
等等。
我是不是做错了什么,忽略了文档中的某些内容?
感谢任何帮助!
编辑:澄清我想要查看结果
编辑2:意外复制了错误的函数名称
编辑3:添加完整的存储过程体,如建议所示。
英文:
We migrated from SQL Server to Postgres and I am trying to rewrite a stored procedure. The procedure is created correctly, but I can not call it.
This is my procedure:
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';
the table-valued-function tvf_commaSeperatedStringToTable
just takes a string, splits it and returns a table with all of the different ids and a rownumber. It works just fine and is tested, no errors inside here.
Now when I try to execute it like this
CALL public.spr_getItems (0, null, null, null)
I get this output:
> ERROR: query has no destination for result data
>
> HINT: If you want to discard the results of a SELECT, use PERFORM instead.
> CONTEXT: PL/pgSQL function spr_getItems(integer,character varying,character varying,character varying) line 3 at SQL statement
> SQL state: 42601
But I do NOT want to discard the result, I want to see them.
So I tried calling it with select
SELECT *
FROM CALL spr_getItems (0, null, null, null)
and then I get this syntax error:
> ERROR: syntax error at or near "0"
> LINE 2: 0,
> ^
> SQL state: 42601
> Character: 40
I also tried executing it in several other way eg by adding the "public." before the procedures name, but then there has been a syntax error at the ".". Or with just using select spr_getItems(0, null, null, null)
or select spr_getItems(0)
, select * from call spr_getItems (0)
and so on and so forth.
Am I doing something completely wrong and overlooked something in the documentation?
Thanks for any help!
Edit: clarification that I want to see the results
Edit2: accidentally copied a wrong function name
Edit3: added complete body as suggested
答案1
得分: 2
这是翻译好的内容:
"这不是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 = ANY (string_to_array(p_referenceIds, ',') OR p_referenceIds IS NULL)
AND (r.oid = ANY (string_to_array(p_resourceIds, ',') 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))
不过,将多个值作为逗号分隔的字符串传递是不好的编码风格。你应该将这些参数声明为数组,并将正确的数组传递给函数。"
英文:
That's not how Postgres works. Procedures aren't meant to return result sets.
If you want that use a set returning function:
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;
You also don't need PL/pgSQL for a simple query encapsulation, language sql
will do just fine.
Then use it like a table:
select *
from spr_getitems(....);
Note that I guessed the data types in the returns table (...)
part, you will have to adjust that to the real types used in your tables.
You don't need the sub-selects to handle the comma separated values either.
E.g. this:
AND (c.referenceOid IN (SELECT refTemp.oid FROM tvf_commaSeperatedStringToTable(p_referenceIds) refTemp) OR p_referenceIds is NULL)
can be simplified to
AND (c.referenceOid = any (string_to_array(p_referenceIds, ',') OR p_referenceIds is NULL)
But passing multiple values as a comma separated string is bad coding style to begin with. You should declare those parameters as array and pass proper arrays to the function.
答案2
得分: 0
你尝试过
EXEC spr_getItems p_kind = 0,
p_customerId = NULL,
p_resourceIds = NULL,
p_referenceIds = NULL
英文:
Have you tried
EXEC spr_getItems p_kind = 0,
p_customerId = NULL,
p_resourceIds = NULL,
p_referenceIds = NULL
答案3
得分: 0
错误是指在 public.spr_getItems 过程内部的函数调用(spr_getshadowrefs)错误。也许您正在尝试执行 spr_getshadowrefs 函数,但没有将结果存储在任何变量中。
<br>
尝试在执行 public.spr_getItems 过程内部的 spr_getshadowrefs 函数时使用 PERFORM。
英文:
The error refers to a function call (spr_getshadowrefs) inside the public.spr_getItems procedure. Perhaps you're trying to execute the spr_getshadowrefs function without putting the result in any variable.
<br>
Try to use PERFORM when you execute the spr_getshadowrefs function inside the public.spr_getItems procedure.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论