【问题标题】:redshift - Not able to apply listagg functionredshift - 无法应用 listagg 功能
【发布时间】:2021-03-15 18:12:38
【问题描述】:

尝试使用listagg 函数时出现错误。

查询

select 
        a.user_name, 
        listagg(a.group_name::text)
within group (order by a.group_name) as group_name
from (
        SELECT 
                usename as user_name, 
                groname as group_name
        FROM 
                pg_user 
        join
                 pg_group
        on 
                pg_user.usesysid = ANY(pg_group.grolist) AND 
                pg_group.groname in (SELECT DISTINCT pg_group.groname from pg_group) 
     )a
     
group by user_name

错误

[代码:500310,SQL 状态:XX000] Amazon 无效操作:必须在至少一个用户创建的表上应用一个或多个使用的函数。仅用户表函数的示例有 LISTAGG、MEDIAN、PERCENTILE_CONT 等;

没有一个值是null

【问题讨论】:

    标签: amazon-web-services amazon-redshift


    【解决方案1】:

    就像有些函数只能在领导节点上运行一样,有些函数只能在计算节点上运行 - listagg() 就是其中之一。如果您需要在领导者数据上运行 list_agg() ,您可以使用以下几种方法:(抱歉,我现在不在集群中,因此无法直接测试这些 - 我看到您的问题已经过时,并认为我会让您开始. 一粒盐,因为我也无法直接观察您的问题,但我想我知道发生了什么。)

    1. 您可以使用游标保存领导节点的数据并使用 这是 list_agg() 的来源。存储过程可以 简化这一点。 stackoverflow 上有这样的例子。
    2. 您可以从领导节点数据中创建一个临时表并使用它 在 list_agg() 但我希望你需要退出(卸载)和 重新进入(复制)集群以执行此操作。

    如果没有某种类型的俯卧撑,就没有从仅领导节点结果到计算节点的直接路径。 Redshift的大型网络集群架构的后果。

    更新

    我有一些集群时间,但这个有几个意想不到的问题。 grolist 是一种数组类型,通常不支持集群范围,并且需要用户 pg_group 作为源是关键。所以这将需要上面的 #1 和 #2。

    流程如下:

    1. 定义游标以保存 pg_user / pg_group join select 语句的结果
    2. 将光标结果移动到临时表
    3. 使用临时表作为外部 (list_agg()) 选择的源

    可以编写一个存储过程来执行 #1 和 #2 以简化事情。所以你最终得到以下 SQL:

    CREATE OR REPLACE procedure make_user_group()
    AS
    $$
    DECLARE 
      row record;
    BEGIN
      --drop table if exists user_group;
      --open cur refcursor;
      create temp table user_group (user_name varchar(256),group_name varchar(256));
      for row in SELECT 
                    usename::text as user_name, 
                    groname::text as group_name
            FROM 
                    pg_user 
            join
                     pg_group
            on 
                    pg_user.usesysid = ANY(pg_group.grolist) AND 
                    pg_group.groname in (SELECT DISTINCT pg_group.groname from pg_group)
       LOOP
        INSERT INTO user_group(user_name,group_name) VALUES (row.user_name,row.group_name);
      END LOOP;
    END;
    $$ LANGUAGE plpgsql;
    
    call make_user_group();
    
    select 
            user_name, 
            listagg(group_name::text)
    within group (order by group_name) as group_name
    from user_group
    group by user_name;
    

    显然存储过程只需要创建一次,但每次需要创建临时表时都会调用。

    【讨论】:

    • 我不认为我了解所有内容。但是我创建了游标并尝试在子查询中使用它并给出错误。
    • @GaurangShah 我用 SQL 更新了答案,并对解决方案进行了更详细的解释。希望这会有所帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-24
    • 1970-01-01
    相关资源
    最近更新 更多