如何创建带参数的 SQL 函数?

Posted

技术标签:

【中文标题】如何创建带参数的 SQL 函数?【英文标题】:How can I create a SQL function with a parameter? 【发布时间】:2012-03-14 19:16:24 【问题描述】:

以下代码根据输入“28”返回一个字段,即一个字符串。

SELECT data.id, LTRIM(SYS_CONNECT_BY_PATH(name, ', '),',') conc_names
  FROM (
     SELECT id, name, ROW_NUMBER() OVER (order by name) rownumber, COUNT(*) OVER () cnt
      FROM (
         SELECT es.EVENT_ID as id, s.SERVICE_NAME as name FROM DT_SERVICES s
            JOIN DT_EVENT_SERVICE es ON s.SERVICE_ID = es.SERVICE_ID
         WHERE es.EVENT_ID = 28
      )
) data
WHERE rownumber = cnt
START WITH rownumber = 1
CONNECT BY PRIOR rownumber = rownumber-1;

如何从中创建一个 SQL 函数,以便我可以传入任何数字(而不是 28),并且该函数将返回该选择的结果是什么?

我尝试创建一个,但我不断收到编译错误。

用于创建函数的当前 SQL

create or replace function "DT_SERVICE_STRING" (id in VARCHAR2)
  return VARCHAR2 is
begin
  DECLARE 
     result VARCHAR(200);
  SELECT data.id, LTRIM(SYS_CONNECT_BY_PATH(name, ', '),',') conc_names
    INTO result
    FROM (
      SELECT id, name, ROW_NUMBER() OVER (order by name) rownumber, COUNT(*) OVER () cnt
      FROM (
        SELECT es.EVENT_ID as id, s.SERVICE_NAME as name FROM DT_SERVICES s
        JOIN DT_EVENT_SERVICE es ON s.SERVICE_ID = es.SERVICE_ID
        WHERE es.EVENT_ID = id
      )
  ) data
  WHERE rownumber = cnt
  START WITH rownumber = 1
  CONNECT BY PRIOR rownumber = rownumber-1;

  return result;
end;​

错误: 编译失败,第 7 行 (15:22:21) PLS-00103:当期望以下之一时遇到符号“SELECT”:开始函数杂注过程子类型类型当前光标删除之前存在

【问题讨论】:

你有什么导致编译错误? 我正在尝试将其创建为 Oracle Apex 中的一个函数 它看起来像什么,这不起作用?使用现有但损坏的代码更新您的问题。 【参考方案1】:

假设您想要一个可从 SQL 语句调用的 PL/SQL 函数(您不能在 SQL 中定义函数),听起来您想要类似的东西

CREATE OR REPLACE FUNCTION get_conc_names( p_event_id IN dt_event_service.event_id%type )
  RETURN VARCHAR2
IS
  l_conc_names VARCHAR2(32676); 
  -- You may want a smaller variable if you know the result will be smaller
BEGIN
  SELECT LTRIM(SYS_CONNECT_BY_PATH(name, ', '),',') conc_names
    INTO l_conc_names
    FROM (
      SELECT id, name, ROW_NUMBER() OVER (order by name) rownumber, COUNT(*) OVER () cnt
        FROM (SELECT es.EVENT_ID as id, s.SERVICE_NAME as name 
                FROM DT_SERVICES s
                     JOIN DT_EVENT_SERVICE es ON s.SERVICE_ID = es.SERVICE_ID
               WHERE es.EVENT_ID = p_event_id )
          ) data
   WHERE rownumber = cnt
   START WITH rownumber = 1
 CONNECT BY PRIOR rownumber = rownumber-1;
  RETURN l_conc_names;
END;

根据您刚刚发布的代码,您似乎只需要去掉DECLARE 并将局部变量result 的声明移到BEGIN 之前和IS 之后。

【讨论】:

确实。现在我明白了:编译失败,第 8 行 (15:27:25) PL/SQL: ORA-00947: not enough valuesCompilation failed,line 7 (15:27:25) PL/SQL: SQL Statement denied @antonpug - 我更新了我的答案。没有注意到您的 SELECT 语句选择了两列。由于您只返回一个值,我假设您真的只需要选择 conc_names 字符串。 嗯,这很奇怪,同样的错误仍然存​​在。是的,我自己也注意到了这两列。它一直告诉我没有足够的价值【参考方案2】:

我认为分析函数需要位于内部内联视图中,然后外部内联视图可以选择它们——这就是我一直这样做的方式。试试这个:

CREATE OR REPLACE FUNCTION get_conc_names( p_event_id IN dt_event_service.event_id%type ) 
  RETURN VARCHAR2 
IS 
  l_conc_names VARCHAR2(32676);  
  -- You may want a smaller variable if you know the result will be smaller 
BEGIN 
  SELECT LTRIM(SYS_CONNECT_BY_PATH(name, ', '),',') conc_names 
    INTO l_conc_names 
    FROM ( 
      SELECT id, name, rownumber, cnt 
        FROM (SELECT es.EVENT_ID as id
                    ,s.SERVICE_NAME as name
                    ,ROW_NUMBER() OVER (order by name) as rownumber
                    ,COUNT(*) OVER () as cnt
                FROM DT_SERVICES s 
                     JOIN DT_EVENT_SERVICE es ON s.SERVICE_ID = es.SERVICE_ID 
               WHERE es.EVENT_ID = p_event_id ) 
             ) data 
    WHERE rownumber = cnt 
    START WITH rownumber = 1 
    CONNECT BY PRIOR rownumber = rownumber-1; 
  RETURN l_conc_names; 
END; 

【讨论】:

以上是关于如何创建带参数的 SQL 函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在java中调用不带参数的PL/SQL函数

带参数的存储过程如何防止 SQL 注入

SQL一个带参数的存储过程写法

带参数的存储过程

SQL Server 如何执行 带参数的 存储过程

带参数的存储过程