Как вернуть запись из существующей таблицы из функции Oracle PL / SQL? - PullRequest
7 голосов
/ 25 февраля 2010

Я знаю, что это кажется простой вещью, но я никогда не делал этого раньше.

Я хотел бы вернуть одну запись из существующей таблицы в результате функции Oracle PL / SQL. Я уже нашел несколько разных способов сделать это, но мне интересен лучший способ сделать это (читай: я не настолько доволен тем, что нашел).

Суть того, что я делаю, заключается в следующем ... У меня есть таблица с именем 'users', и я хочу, чтобы функция 'update_and_get_user', которой присвоено имя пользователя (а также другая доверенная информация о указанном пользователе), потенциально могла выполнять различные действия с таблицей 'users', а затем вернуть либо ноль, либо одну строку / запись из указанной таблицы.

Это основной набросок кода в моей голове на данный момент (читай: понятия не имею, синтаксис даже близок к правильному):

CREATE FUNCTION update_and_get_user(UserName in VARCHAR2, OtherStuff in VARCHAR2)
    RETURN users PIPELINED IS
  TYPE ref0 IS REF CURSOR;
  cur0       ref0;
  output_rec users%ROWTYPE;
BEGIN
  -- Do stuff

  -- Return the row (or nothing)
  OPEN cur0 FOR 'SELECT * FROM users WHERE username = :1'
    USING UserName;

  LOOP
    FETCH cur0 INTO output_rec;
    EXIT WHEN cur0%NOTFOUND;
    PIPE ROW(output_rec);
  END LOOP;
END update_and_get_user;

Я видел примеры, когда возвращалась запись или таблица, тип записи или таблицы был создан / объявлен заранее, но похоже, что если таблица уже была определена, я смогу использовать это, и таким образом, не нужно беспокоиться о синхронизации кода объявления типа, если когда-либо вносятся изменения в таблицу.

Я открыт для всех потенциальных решений и комментариев, но я действительно действительно хочу сохранить это в одной функции PL / SQL (в отличие от кода на каком-либо другом языке / фреймворке, который взаимодействует с базы данных несколько раз, заканчивая некоторой формой «SELECT * FROM users WHERE username = blah»), поскольку система, вызывающая функцию, и сама база данных могут быть разными городами. За пределами этого предела я готов изменить свое мышление.

1 Ответ

13 голосов
/ 25 февраля 2010

Вот как бы я это сделал. Переменные / имена таблиц / имена столбцов не чувствительны к регистру в Oracle, поэтому я бы использовал user_name вместо UserName.

CREATE TABLE users( UserName varchar2(20), OtherStuff VARCHAR2(20) );

Функция update_and_get_user. Обратите внимание, что я возвращаю ROWTYPE вместо конвейерных таблиц.

CREATE OR REPLACE FUNCTION update_and_get_user(
  in_UserName   IN users.UserName%TYPE,
  in_OtherStuff IN users.OtherStuff%TYPE )
RETURN users%ROWTYPE
IS
  output_rec users%ROWTYPE;
BEGIN
  UPDATE users
  SET OtherStuff = in_OtherStuff
  WHERE UserName = in_UserName
    RETURNING UserName, OtherStuff
    INTO output_rec;
  RETURN output_rec;
END update_and_get_user;

И вот как вы бы это назвали. Вы не можете проверить ROWTYPE как NULL, но вы можете проверить username, например.

DECLARE
  users_rec users%ROWTYPE;
BEGIN
  users_rec := update_and_get_user('user', 'stuff');
  IF( users_rec.username IS NOT NULL ) THEN
    dbms_output.put_line('FOUND: ' || users_rec.otherstuff);
  END IF;
END;

Ниже приведено решение, использующее PIPED ROWS, но оно не работает таким образом. Вы не можете обновить таблицы внутри запроса.

SELECT * FROM TABLE(update_and_get_user('user', 'stuff'))

ORA-14551: cannot perform a DML operation inside a query

Решение будет выглядеть так:

CREATE OR REPLACE TYPE users_type
AS OBJECT
(
  username   VARCHAR2(20),
  otherstuff VARCHAR2(20)
)

CREATE OR REPLACE TYPE users_tab
   AS TABLE OF users_type;

CREATE OR REPLACE FUNCTION update_and_get_user(
  in_UserName   IN users.username%TYPE,
  in_OtherStuff IN users.otherstuff%TYPE )
RETURN users_tab PIPELINED
IS
  output_rec users%ROWTYPE;
BEGIN
  UPDATE users
  SET OtherStuff = in_OtherStuff
  WHERE UserName = in_UserName
    RETURNING username, otherstuff
    INTO output_rec;
  PIPE ROW(users_type(output_rec.username, output_rec.otherstuff));
END;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...