Почему Oracle разрешает иметь несколько подзапросов с одним и тем же именем alias в предложении WITH?

Это выглядит немного смешно, но Oracle 11g действительно разрешает запуск такого запроса

with
    a as (select 1 from dual),
    a as (select 2 from dual)
select  *
from    a;

Он возвращает результат первого подзапроса (т.е. 1).

Я просто не могу представить ситуацию, когда такая функция может быть полезна. В моем случае это скорее вызвало проблему, когда я забыл переименовать подзапрос после копирования/вставки его, а общий запрос возвращал неправильные/неожиданные результаты. К счастью, запрос был довольно простым, и причина была обнаружена сразу.

Во всяком случае, я бы ожидал, что Oracle сделает бросок и исключение в таком случае.

Итак, мой вопрос заключается в том, является ли такое поведение особенностью или ошибкой? Если функция, где она может быть полезна?

Спасибо.

BTW, SQLite не разрешает запуск аналогичного запроса и исключает исключение "дубликат WITh table name". Больше не пытались использовать другие двигатели.

Ответы

Ответ 1

Предложение WITH также может использоваться с функциями. Я не уверен, что это было доступно с 11g, но оно с 12c. Таким образом, эта " ошибка" может потребоваться для перегруженных функций.

Например, эта процедура использует одну и ту же функцию дважды, с теми же типами данных ввода/вывода.

WITH 
   FUNCTION get_date(pid IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN 'date is '|| pid;
END;
  FUNCTION get_date(pid IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN 'date is '|| pid;
END;
SELECT get_date(cast(sysdate as varchar2(20)))
FROM   dual  
;
/

Как и ожидалось, он возвращает ошибку:

ORA-06553: PLS-305: previous use of 'GET_DATE' (at line 1) conflicts with this use

Но если вы перегружаете функцию, то она имеет то же имя, но принимает разные типы параметров, она будет работать. Процедура будет работать без ошибок, и в зависимости от типа переменных данных используется правильная функция.

WITH 
   FUNCTION get_date(pid IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN 'date is '|| pid;
END;
  FUNCTION get_date(pid IN DATE) RETURN VARCHAR2 IS
BEGIN
RETURN pid+1;
END;
SELECT 
get_date(cast(sysdate as varchar2(20))) /*example1*/
--get_date(sysdate)                    /*example2*/
FROM   dual  
;
/

Пример 1: date is 16-MAR-17 Пример 2: 17-MAR-17

Поэтому возможно использование подзапросов с тем же именем связано с возможностью перегрузки функций. Хотя это все еще кажется ошибкой, и я не смог найти документацию по этому вопросу.

Ответ 2

Это не полезно, но это согласуется с тем, как Oracle обрабатывает дубликаты имен столбцов.