'How can a function within a with block use a table defined in this same with block

WITH
    FUNCTION f (a in integer)
        RETURN INTEGER
    IS
        ret integer;
    BEGIN
        SELECT COUNT (*) into ret
        FROM B;
        RETURN ret +a;
    END;
B(b1) as (select 1 from dual),
select f(3) from dual;

Oracle say :

[Error] Execution (6: 1): ORA-06552: PL/SQL: ORA-00942: table or view does not exist

dbfiddle (https://dbfiddle.uk/?rdbms=oracle_21&fiddle=ff90cec6ed25724bad9c215f0173607a)say :

ORA-00903: invalid table name

I think that Oracle doesn't know the table B because, she is defined after f is defined. But I can't change the order of what is defined in a with block. The functions must be defined before the table.

Does somebody has a solution to use in a function a table which is defined in the same with block?

I can't declare the B table inside the function, because I intend to create others function that use the table B. I don't want to defined B more than 2 times.



Solution 1:[1]

Declare B inside the function:

WITH FUNCTION f (a in integer)
  RETURN INTEGER
IS
  ret integer;
BEGIN
  WITH B(b1) AS (
    SELECT 1 FROM DUAL
  )
  SELECT COUNT (*) into ret
  FROM B;
  RETURN ret +a;
END;
SELECT f(3)
FROM   DUAL;

Or, do the counting outside the function:

WITH FUNCTION f (
  a   IN PLS_INTEGER,
  cnt IN PLS_INTEGER
)
  RETURN INTEGER
IS
BEGIN
  RETURN cnt +a;
END;
B (b1) AS (
  SELECT 1 FROM DUAL
)
SELECT f(3, (SELECT COUNT(*) FROM b)) AS value
FROM   DUAL;

Which both output:

VALUE
4

However

If you want to COUNT inside the function and reference a subquery factoring clause that is defined later then you are out of luck as you need to have the table defined before the function.

The syntax diagram states:

select::=

SELECT syntax

subquery::=

SUBQUERY syntax

query_block::=

QUERY_BLOCK syntax

with_clause::=

WITH_CLAUSE

subquery_factoring_clause::=

SUBQUERY_FACTORING_CLAUSE syntax

Although there is a clear chain in the syntax diagram SELECT, SUBQUERY, QUERY_BLOCK, WITH_CLAUSE, SUBQUERY_FACTORING_CLAUSE and back to SUBQUERY if, in practice you try to do something like nesting WITH clauses:

WITH B (b1) AS (
  SELECT 1 FROM DUAL
),
C (value) AS (
  WITH FUNCTION f (a in integer)
    RETURN INTEGER
  IS
    ret integer;
  BEGIN
    SELECT COUNT (*) into ret
    FROM B;

    RETURN ret +a;
  END f;
  SELECT f(3)
  FROM   DUAL 
)
SELECT value
FROM   c;

You will get the error:

ORA-32034: unsupported use of WITH clause

db<>fiddle here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MT0