Эта статья может быть слишком технической для понимания большинства читателей . ( Апрель 2018 ) |
Иерархический запрос — это тип SQL-запроса , который обрабатывает данные иерархической модели . Они являются частными случаями более общих рекурсивных запросов с фиксированной точкой , которые вычисляют транзитивные замыкания .
В стандарте SQL:1999 иерархические запросы реализуются посредством рекурсивных общих табличных выражений (CTE). В отличие от более раннего предложения Oracle connect-by, рекурсивные CTE были разработаны с семантикой фиксированной точки с самого начала. [1] Рекурсивные CTE из стандарта были относительно близки к существующей реализации в IBM DB2 версии 2. [1] Рекурсивные CTE также поддерживаются Microsoft SQL Server (начиная с SQL Server 2008 R2), [2] Firebird 2.1 , [3] PostgreSQL 8.4+ , [4] SQLite 3.8.3+ , [5] IBM Informix версии 11.50+, CUBRID , MariaDB 10.2+ и MySQL 8.0.1+ . [6] Tableau имеет документацию, описывающую, как можно использовать CTE. TIBCO Spotfire не поддерживает CTE, а в реализации Oracle 11g Release 2 отсутствует семантика фиксированных точек.
Без общих табличных выражений или связанных предложений можно реализовать иерархические запросы с помощью определяемых пользователем рекурсивных функций. [7]
Этот раздел нуждается в расширении . Вы можете помочь, дополнив его. ( Ноябрь 2012 ) |
Общее табличное выражение (CTE) (в SQL ) — это временный именованный набор результатов, полученный из простого запроса и определенный в области выполнения оператора SELECT
, INSERT
, UPDATE
, или DELETE
.
CTE можно рассматривать как альтернативу производным таблицам ( подзапросам ), представлениям и встроенным пользовательским функциям.
Общие табличные выражения поддерживаются Teradata (начиная с версии 14), IBM Db2 , Informix (начиная с версии 14.1), Firebird (начиная с версии 2.1), [8] Microsoft SQL Server (начиная с версии 2005), Oracle (с рекурсией с 11g release 2), PostgreSQL (начиная с версии 8.4), MariaDB (начиная с версии 10.2 [9] ), MySQL (начиная с версии 8.0), SQLite (начиная с версии 3.8.3), HyperSQL , Informix (начиная с версии 14.10), [10] Google BigQuery , Sybase (начиная с версии 9), Vertica , H2 (экспериментально), [11] и многими другими . Oracle называет CTE «subquery factoring». [12]
Синтаксис CTE (который может быть рекурсивным или нет) выглядит следующим образом:
С [ РЕКУРСИВНЫМ ] с_запросом [, ...] ВЫБРАТЬ ...
где with_query
синтаксис:
имя_запроса [ ( имя_столбца [,...]) ] КАК ( ВЫБРАТЬ ...)
Рекурсивные CTE можно использовать для обхода отношений (как графы или деревья), хотя синтаксис гораздо сложнее, поскольку не создаются автоматически псевдостолбцы (как LEVEL
ниже); если они нужны, их нужно создать в коде. См. документацию MSDN [2] или документацию IBM [13] [14] для учебных примеров.
Ключевое RECURSIVE
слово обычно не требуется после WITH в системах, отличных от PostgreSQL. [15]
В SQL:1999 рекурсивный (CTE) запрос может появляться везде, где разрешен запрос. Например, можно назвать результат с помощью CREATE
[ RECURSIVE
] VIEW
. [16] Используя CTE внутри INSERT INTO
, можно заполнить таблицу данными, сгенерированными из рекурсивного запроса; случайная генерация данных возможна с использованием этой техники без использования каких-либо процедурных операторов. [17]
Некоторые базы данных, такие как PostgreSQL, поддерживают более короткий формат CREATE RECURSIVE VIEW, который внутренне транслируется в кодировку WITH RECURSIVE. [18]
Пример рекурсивного запроса, вычисляющего факториал чисел от 0 до 9, выглядит следующим образом:
WITH recursive temp ( n , fact ) AS ( SELECT 0 , 1 — Начальный подзапрос UNION ALL SELECT n + 1 , ( n + 1 ) * fact FROM temp WHERE n < 9 — Рекурсивный подзапрос ) SELECT * FROM temp ;
Альтернативный синтаксис — нестандартная CONNECT BY
конструкция; она была введена Oracle в 1980-х годах. [19] До Oracle 10g конструкция была полезна только для обхода ациклических графов, поскольку она возвращала ошибку при обнаружении любых циклов; в версии 10g Oracle представила функцию NOCYCLE (и ключевое слово), благодаря чему обход работал и при наличии циклов. [20]
CONNECT BY
поддерживается Snowflake , EnterpriseDB , [21] базой данных Oracle , [22] CUBRID , [23] IBM Informix [24] и IBM Db2 , но только если он включен как режим совместимости. [25] Синтаксис следующий:
SELECT select_list FROM table_expression [ WHERE ... ] [ START WITH start_expression ] CONNECT BY [ NOCYCLE ] { PRIOR child_expr = parent_expr | parent_expr = PRIOR child_expr } [ ORDER SIBLINGS BY column1 [ ASC | DESC ] [, column2 [ ASC | DESC ] ] ... ] [ GROUP BY ... ] [ HAVING ... ] ...
ВЫБРАТЬ УРОВЕНЬ , LPAD ( ' ' , 2 * ( УРОВЕНЬ - 1 )) || ename "сотрудник" , empno , mgr "менеджер" ИЗ emp НАЧАТЬ С mgr ЕСТЬ NULL ПОДКЛЮЧИТЬ ПО ПРЕДЫДУЩЕЙ empno = mgr ;
Вывод приведенного выше запроса будет выглядеть следующим образом:
уровень | сотрудник | empno | менеджер-------+-------------+-------+--------- 1 | КОРОЛЬ | 7839 | 2 | ДЖОНС | 7566 | 7839 3 | СКОТТ | 7788 | 7566 4 | АДАМС | 7876 | 7788 3 | ФОРД | 7902 | 7566 4 | СМИТ | 7369 | 7902 2 | БЛЕЙК | 7698 | 7839 3 | АЛЛЕН | 7499 | 7698 3 | ОТДЕЛЕНИЕ | 7521 | 7698 3 | МАРТИН | 7654 | 7698 3 | ТЕРНЕР | 7844 | 7698 3 | ДЖЕЙМС | 7900 | 7698 2 | КЛАРК | 7782 | 7839 3 | МИЛЛЕР | 7934 | 7782(14 рядов)
Следующий пример возвращает фамилию каждого сотрудника в отделе 10, каждого менеджера, находящегося выше этого сотрудника в иерархии, количество уровней между менеджером и сотрудником и путь между ними:
SELECT ename "Сотрудник" , CONNECT_BY_ROOT ename "Менеджер" , LEVEL - 1 "Pathlen" , SYS_CONNECT_BY_PATH ( ename , '/' ) "Путь" FROM emp WHERE LEVEL > 1 AND deptno = 10 CONNECT BY PRIOR empno = mgr ORDER BY "Сотрудник" , "Менеджер" , "Pathlen" , "Путь" ;
SYS_CONNECT_BY_PATH
Учебники . Обратите внимание, что они охватывают только стандарт SQL:1999 (и Datalog), но не расширение Oracle.