Oracle динамический SQL с нулевыми параметрами - PullRequest
0 голосов
/ 10 октября 2018

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

-- Update client
create or replace procedure p_update_client (i_client_id in number, i_iin in number default null, i_full_name in varchar default null)
as
query_str varchar(200);
no_id_provided exception;
all_null_values exception;
begin
-- Handle input parameters
if i_client_id is null then
    raise no_id_provided;
end if;
if i_iin is null and i_full_name is null then
    raise all_null_values;
end if;

-- Base query string.
query_str := 'update t_client set';
-- Form SQL depending on the input parameters.
if i_iin is not null then
    query_str := query_str || ' iin = :param1';
end if;
if i_full_name is not null then
    query_str := query_str || ' full_name = :param2';
end if;
-- Add necessary where clause to identify record.
query_str := query_str || ' where client_id = :param3;';

-- Execute query.
execute immediate query_str using i_iin, i_full_name, i_client_id;
exception
when no_id_provided then
    raise_application_error(-20100, 'Client_id value must not be null.');
when all_null_values then
    raise_application_error(-20101, 'To update record, input parameters must not be null.');
when others then
    rollback;
end p_update_client;

Итак, логика процедуры следующая: если переданный параметр имеет ненулевое значение, то я динамически обновляю свойSQL и выполните его, используя execute immidiate.Это прекрасно работает, если оба параметра имеют ненулевые значения.Если один из параметров имеет значение NULL, query_str выдаст ошибку SQL ORA-01006: bind variable does not exist, поскольку число параметров, указанное в query_str, не совпадает с параметром using.

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

1 Ответ

0 голосов
/ 10 октября 2018

На вашем месте я не стал бы беспокоиться о динамическом утверждении.Вместо этого я бы использовал COALESCE() (или вы могли бы использовать NVL()), чтобы решить, что использовать для обновления столбца, так что ваша процедура будет выглядеть примерно так:

-- Update client
CREATE OR REPLACE PROCEDURE p_update_client(i_client_id IN NUMBER,
                                            i_iin       IN NUMBER DEFAULT NULL,
                                            i_full_name IN VARCHAR DEFAULT NULL) AS
  no_id_provided  EXCEPTION;
  all_null_values EXCEPTION;
BEGIN
  -- Handle input parameters
  IF i_client_id IS NULL
  THEN
    RAISE no_id_provided;
  END IF;
  IF i_iin IS NULL
     AND i_full_name IS NULL
  THEN
    RAISE all_null_values;
  END IF;  

  UPDATE t_client
  SET    iin = COALESCE(i_iin, iin),
         full_name = COALESCE(i_full_name, full_name)
  WHERE  client_id = i_client_id;

EXCEPTION
  WHEN no_id_provided THEN
    raise_application_error(-20100, 'Client_id value must not be null.');
  WHEN all_null_values THEN
    raise_application_error(-20101, 'To update record, input parameters must not be null.');
  WHEN OTHERS THEN
    ROLLBACK;
END p_update_client;
/

Возможно, вы захотитедобавьте дополнительный предикат в соответствии с:

  AND    (iin != COALESCE(i_iin, iin)
          OR full_name != COALESCE(i_full_name, full_name))

к оператору обновления, чтобы, если передаваемые значения совпадали с текущими значениями для столбца, обновление фактически не происходило (это было бытрата времени).

...