我编写了以下调用 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
在查询中:
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 |