Oracle SELECT INTO: синтаксис, использование и примеры

SELECT INTO - это удобный инструмент SQL в Oracle для эффективной работы с данными. Он позволяет выбирать данные из таблиц базы данных и сохранять результат в переменные или коллекции PL/SQL.

Синтаксис оператора SELECT INTO

Рассмотрим базовый синтаксис конструкции SELECT INTO:

SELECT column1, column2, ... INTO variable1, variable2, ... FROM table_name WHERE condition;

Здесь происходит выборка значений указанных столбцов в соответствующие переменные. Количество столбцов и переменных должно совпадать.

Выборка в запись

Чтобы сохранить результат запроса целиком в запись, используется следующий синтаксис:

SELECT * INTO record_variable FROM table_name WHERE condition;

Запись record_variable должна иметь такую же структуру, как и выбираемая строка таблицы.

Выборка множества значений

Часто нужно получить сразу несколько строк результата. Для этого применяется конструкция SELECT INTO с предложением BULK COLLECT:

SELECT column1, column2, ... BULK COLLECT INTO variable1, variable2, ... FROM table_name WHERE condition;

Результат сохраняется в коллекции - массивы, вложенные таблицы и т.д. Это more efficient, than using loops.

Использование псевдонимов (aliases)

В SELECT INTO можно задавать псевдонимы для столбцов:

SELECT column_1 AS alias_1, column_2 AS alias_2 INTO variable_1, variable_2 FROM table_name;

Это позволяет давать переменным более удобные имена.

Обработка исключительных ситуаций

Нужно отлавливать как минимум две ошибки:

  • TOO_MANY_ROWS - если запрос возвращает больше одной строки
  • NO_DATA_FOUND - если запрос не возвращает ни одной строки

Например:

BEGIN SELECT ... INTO ... FROM ... WHERE ...; EXCEPTION WHEN TOO_MANY_ROWS THEN ... WHEN NO_DATA_FOUND THEN ... END;

Рекомендации по применению SELECT INTO

Использование SELECT INTO имеет ряд преимуществ по сравнению с построчной выборкой данных в цикле.

Преимущества перед циклом с FETCH

  • Меньше кода
  • Быстрее работает
  • Удобнее отлаживать

Однако есть и ограничения:

  • Максимальный размер выборки ограничен
  • Нельзя выбирать BLOB или CLOB столбцы
  • Риск получить слишком много данных

Поэтому в зависимости от задачи приходится выбирать подходящую стратегию.

Работа с составными типами данных

При сохранении в переменные записей, объектов и коллекций нужно следить за совместимостью типов данных.

Например, чтобы выбрать nestet table столбец, используется:

SELECT column1, TABLE(column2) INTO variable1, variable2 FROM table_name;

oracle select into примеры использования

Рассмотрим примеры применения SELECT INTO для решения практических задач.

Загрузка данных из CSV

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

CREATE GLOBAL TEMPORARY TABLE temp_data ( id NUMBER, name VARCHAR2(50) ) ON COMMIT PRESERVE ROWS; DECLARE f UTL_FILE.FILE_TYPE; v_id TEMP_DATA.ID%TYPE; v_name TEMP_DATA.NAME%TYPE; BEGIN f := UTL_FILE.FOPEN('TMP_DIR', 'data.csv', 'r'); LOOP UTL_FILE.GET_LINE(f, v_line); v_id := REGEXP_SUBSTR(v_line, '[^,]+', 1, 1); v_name := REGEXP_SUBSTR(v_line, '[^,]+', 1, 2); INSERT INTO temp_data VALUES (v_id, v_name); END LOOP; UTL_FILE.FCLOSE(f); END;

Здесь мы построчно читаем данные из CSV файла и INSERT их во временную таблицу temp_data с помощью SELECT INTO.

Такой подход позволяет быстро загрузить любые данные в Oracle!

Выгрузка данных в файлы

SELECT INTO также удобно использовать для выгрузки данных из Oracle во внешние файлы. Например, экспортируем содержимое таблицы в CSV:

DECLARE f UTL_FILE.FILE_TYPE; v_id TABLE_NAME.ID%TYPE; v_name TABLE_NAME.NAME%TYPE; BEGIN f := UTL_FILE.FOPEN('TMP_DIR', 'export.csv', 'w'); FOR item IN (SELECT * FROM table_name) LOOP SELECT id, name INTO v_id, v_name FROM table_name WHERE id = item.id; UTL_FILE.PUT_LINE(f, v_id || ',' || v_name); END LOOP; UTL_FILE.FCLOSE(f); END;

Здесь мы используем курсор для построчного чтения данных с последующей выборкой каждой строки в переменные через SELECT INTO. Это позволяет гибко управлять данными перед записью в CSV файл.

Генерация отчетов

При формировании различных отчетов на основании данных из БД часто применяется SELECT INTO.

Например, посчитаем количество заказов за период в разрезе клиентов:

DECLARE v_cust_id orders.customer_id%TYPE; v_cust_name customers.name%TYPE; v_orders NUMBER; CURSOR c_orders IS SELECT customer_id, COUNT(*) cnt FROM orders WHERE order_date BETWEEN :start_date AND :end_date GROUP BY customer_id; BEGIN FOR r_order IN c_orders LOOP SELECT name INTO v_cust_name FROM customers WHERE id = r_order.customer_id; DBMS_OUTPUT.PUT_LINE(r_order.customer_id || ' ' || v_cust_name || ' ' || r_order.cnt); END LOOP; END;

Здесь мы выбираем данные с группировкой и подсчетом, а затем дополняем отчет именами клиентов из другой таблицы с помощью SELECT INTO.

Оптимизация запросов

Иногда применение SELECT INTO позволяет ускорить выполнение запросов за счет кеширования промежуточных результатов.

Например, при выборке данных из нескольких таблиц можно сначала сохранить ключи связи в переменные, а затем использовать их в основном запросе:

DECLARE v_empl_id employees.id%TYPE; v_dept_id employees.department_id%TYPE; BEGIN SELECT id, department_id INTO v_empl_id, v_dept_id FROM employees WHERE email = 'name@company.com'; SELECT * FROM employees e JOIN departments d ON d.id = v_dept_id WHERE e.id = v_empl_id; END;

Такой подход помогает снизить нагрузку на оптимизатор запросов и ускорить работу с большими объемами данных.

Комментарии