You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL自定义函数出现syntax error at or near "ARRAY"错误求助

PostgreSQL函数语法错误排查:syntax error at or near "ARRAY"

问题描述

我是编程新手,编写了PostgreSQL建表语句及自定义函数get_services_auth_data,执行时出现错误:syntax error at or near "ARRAY"。代码中涉及数组的部分为results services_auth_data[] := '{}'和函数参数services TEXT[],需要找出错误原因。

原代码如下:

DROP TABLE IF EXISTS "public"."services_auth_data";

DROP FUNCTION IF EXISTS public.get_services_auth_data;

create table "public"."services_auth_data" (
    "service_name" text not null,
    "token" text not null,
    "admin_email" text, 
    "org" text
);

CREATE OR REPLACE FUNCTION get_services_auth_data(services TEXT[])
RETURNS SETOF services_auth_data AS $$
DECLARE
  email TEXT := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'email');
  workspace_name TEXT := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'hd');
  name TEXT := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'name');
  is_admin BOOLEAN := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'isAdmin')::BOOLEAN;
  w_id BIGINT := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'workspace_id')::BIGINT;
  service_result services_auth_data;
  results services_auth_data[] := '{}';
  _token text;
  _org text;
  _admin_email text; 
  service_name text;
BEGIN
  FOR service_name IN ARRAY services LOOP
    IF service_name = 'github' THEN
      SELECT service_github.org, service_github.token INTO _org, _token FROM service_github WHERE id = w_id;
      service_result.org = _org;
      service_result.token = _token;
      service_result.service_name = service_name;
      results := array_append(results, service_result);
    ELSIF service_name = 'jira' THEN
      SELECT service_jira.admin_email, service_jira.token INTO _admin_email, _token FROM service_jira WHERE id = w_id;
      service_result.admin_email = _admin_email;
      service_result.token = _token;
      service_result.service_name = service_name;
      results := array_append(results, service_result);
    ELSIF service_name = 'zoom' THEN
      SELECT service_zoom.token INTO _token FROM service_zoom WHERE id = w_id;
      service_result.token = _token;
      service_result.service_name = service_name;
      results := array_append(results, service_result);
    ELSE
      RAISE EXCEPTION 'Invalid service name or missing params: %', service_name;
    END IF;
  END LOOP;
  
  return query select * from unnest(results);
END;
$$ LANGUAGE plpgsql;

错误原因

错误出现在FOR service_name IN ARRAY services LOOP这一行。PostgreSQL的PL/pgSQL中,遍历数组不能用FOR ... IN ARRAY ...的语法,正确的数组遍历方式有两种:

  1. 使用FOREACH关键字直接遍历数组元素
  2. 通过SELECT UNNEST()将数组转为结果集后用FOR ... IN ...遍历

修正后的代码

方式一:使用FOREACH(推荐)

把原循环部分替换为FOREACH service_name IN ARRAY services LOOP,完整代码如下:

DROP TABLE IF EXISTS "public"."services_auth_data";

DROP FUNCTION IF EXISTS public.get_services_auth_data;

create table "public"."services_auth_data" (
    "service_name" text not null,
    "token" text not null,
    "admin_email" text, 
    "org" text
);

CREATE OR REPLACE FUNCTION get_services_auth_data(services TEXT[])
RETURNS SETOF services_auth_data AS $$
DECLARE
  email TEXT := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'email');
  workspace_name TEXT := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'hd');
  name TEXT := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'name');
  is_admin BOOLEAN := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'isAdmin')::BOOLEAN;
  w_id BIGINT := ((current_setting('request.jwt.claims'::TEXT, TRUE))::JSON ->> 'workspace_id')::BIGINT;
  service_result services_auth_data;
  results services_auth_data[] := '{}';
  _token text;
  _org text;
  _admin_email text; 
  service_name text;
BEGIN
  FOREACH service_name IN ARRAY services LOOP
    IF service_name = 'github' THEN
      SELECT service_github.org, service_github.token INTO _org, _token FROM service_github WHERE id = w_id;
      service_result.org = _org;
      service_result.token = _token;
      service_result.service_name = service_name;
      results := array_append(results, service_result);
    ELSIF service_name = 'jira' THEN
      SELECT service_jira.admin_email, service_jira.token INTO _admin_email, _token FROM service_jira WHERE id = w_id;
      service_result.admin_email = _admin_email;
      service_result.token = _token;
      service_result.service_name = service_name;
      results := array_append(results, service_result);
    ELSIF service_name = 'zoom' THEN
      SELECT service_zoom.token INTO _token FROM service_zoom WHERE id = w_id;
      service_result.token = _token;
      service_result.service_name = service_name;
      results := array_append(results, service_result);
    ELSE
      RAISE EXCEPTION 'Invalid service name or missing params: %', service_name;
    END IF;
  END LOOP;
  
  return query select * from unnest(results);
END;
$$ LANGUAGE plpgsql;

方式二:使用SELECT UNNEST

如果坚持用FOR循环,可将循环行改为:

FOR service_name IN SELECT UNNEST(services) LOOP

补充说明

  • FOREACH是PL/pgSQL中专门用于遍历数组的语法,写法更简洁直接
  • UNNEST()函数的作用是将数组拆分为单行的结果集,适合用在FOR ... IN SELECT ...的场景中

内容的提问来源于stack exchange,提问作者Alwaysblue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:45:12