从函数调用 Oracle LISTAGG 函数

问题描述 投票:0回答:1

我编写了以下调用 LISTAGG 函数的 Oracle PL/SQL 函数

create or replace function PK_LIST(SCHEMA_NM IN varchar2, TABLE_NM IN varchar2)
    return varchar2
is
    P_KEY varchar(4000);
begin
        select
            LISTAGG(
                    A.COLUMN_NAME,
                    ', '
                )
                within group (order by A.COLUMN_NAME)
                into P_KEY 
        from
                ALL_TAB_COLUMNS A
                left join ALL_CONS_COLUMNS ACC ON A.COLUMN_NAME = ACC.COLUMN_NAME
                     and A.TABLE_NAME = ACC.TABLE_NAME
                     and A.OWNER = ACC.OWNER
                left join ALL_CONSTRAINTS AC 
                    on AC.CONSTRAINT_NAME = ACC.CONSTRAINT_NAME
                    and AC.OWNER = ACC.OWNER
            where
                AC.CONSTRAINT_TYPE = 'P'
                and A.OWNER = SCHEMA_NM
                and A.TABLE_NAME = TABLE_NM;

        return P_KEY;
    end;

select TABLE_NAME, PK_LIST(A.OWNER, A.TABLE_NAME) as MY_LIST
from ALL_TABLES A
where OWNER = 'xxx'-- enter any User/Owner in place of xxx;

当我执行此代码时,函数返回 NULL,但是当我执行下面的 SQL select 语句时,代码似乎工作正常。

declare
    PK_LIST varchar2(4000);
begin
    select
        LISTAGG(
                A.COLUMN_NAME,
                ', '
                )
                within group (order by A.COLUMN_NAME)
                into PK_LIST 
    from ALL_TAB_COLUMNS A
        left join ALL_CONS_COLUMNS ACC ON A.COLUMN_NAME = ACC.COLUMN_NAME
                AND A.TABLE_NAME = ACC.TABLE_NAME
                AND A.OWNER = ACC.OWNER
        left join ALL_CONSTRAINTS AC ON AC.CONSTRAINT_NAME = ACC.CONSTRAINT_NAME
                AND AC.OWNER = ACC.OWNER
        where
            AC.CONSTRAINT_TYPE = 'P'
            and A.OWNER = 'SRSODS'
            and A.TABLE_NAME = 'CONTRACT';

    dbms_output.put_line(PK_LIST);
end;

为什么这个函数调用会返回预期的结果?

结果:我期待表格的主键的逗号分隔列表,如下所示:

ACCOUNT_NBR、BRANCH_NBR、COUNTRY_CD

sql oracle plsql
1个回答
0
投票

在查询中:

SELECT LISTAGG(A.COLUMN_NAME, ', ')
         WITHIN GROUP (ORDER BY A.COLUMN_NAME)
INTO   P_KEY 
FROM   ALL_TAB_COLUMNS A
       LEFT OUTER JOIN ALL_CONS_COLUMNS ACC
       ON A.COLUMN_NAME = ACC.COLUMN_NAME
          AND A.TABLE_NAME = ACC.TABLE_NAME
          AND A.OWNER = ACC.OWNER
       LEFT OUTER JOIN ALL_CONSTRAINTS AC 
       ON AC.CONSTRAINT_NAME = ACC.CONSTRAINT_NAME
          AND AC.OWNER = ACC.OWNER
WHERE  AC.CONSTRAINT_TYPE = 'P'
AND    A.OWNER = SCHEMA_NM
AND    A.TABLE_NAME = TABLE_NM;

线路:

WHERE  AC.CONSTRAINT_TYPE = 'P'

意味着

AC
表中必须有一行
CONSTRAINT_TYPE = 'P'
并有效地将所有
LEFT OUTER JOIN
转换为
INNER JOIN
,因为除非在两个连接的右侧。

要修复此问题,请将过滤器移至连接的

ON
子句:

CREATE FUNCTION PK_LIST(
  SCHEMA_NM IN ALL_TAB_COLUMNS.OWNER%TYPE,
  TABLE_NM  IN ALL_TAB_COLUMNS.TABLE_NAME%TYPE
) RETURN VARCHAR2
IS
  P_KEY varchar(4000);
BEGIN
  SELECT LISTAGG(A.COLUMN_NAME, ', ')
           WITHIN GROUP (ORDER BY A.COLUMN_NAME)
  INTO   P_KEY 
  FROM   ALL_TAB_COLUMNS A
         LEFT OUTER JOIN ALL_CONS_COLUMNS ACC
         ON A.COLUMN_NAME = ACC.COLUMN_NAME
            AND A.TABLE_NAME = ACC.TABLE_NAME
            AND A.OWNER = ACC.OWNER
         LEFT OUTER JOIN ALL_CONSTRAINTS AC 
         ON AC.CONSTRAINT_NAME = ACC.CONSTRAINT_NAME
            AND AC.OWNER = ACC.OWNER
            AND AC.CONSTRAINT_TYPE = 'P'
  WHERE  A.OWNER = SCHEMA_NM
  AND    A.TABLE_NAME = TABLE_NM;

  RETURN P_KEY;
END;
/

如果你有桌子:

CREATE TABLE table1 (id NUMBER PRIMARY KEY);
CREATE TABLE table2 (id1 NUMBER, id2 NUMBER, PRIMARY KEY (id1, id2));

然后:

select TABLE_NAME, PK_LIST(A.OWNER, A.TABLE_NAME) as MY_LIST
from   ALL_TABLES A
where  OWNER = USER

输出:

表名称 我的_列表
表1 身份证
表2 ID1、ID2

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.