0

I have the following procedure, that updates client's info depending on the input parameters.

-- 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;

So, procedure's logic is the following: if passed parameter has non-null value, then I dynamicaly update my SQL and execute it using execute immidiate. This works fine as long as both parameters has non-null values. If one of the parameters is null, then query_str will throw an SQL error ORA-01006: bind variable does not exist because number of parameters, specified in the query_str is not the same as in using clause.

What is the better way to handle such situation, maybe sone kind of named parameters, but as I know, execute emmidiate does not provide that. Any ideas?

1 Answer 1

1

If I were you, I wouldn't bother with a dynamic statement. Instead, I'd use COALESCE() (or you could use NVL()) to decide what to use to update the column with, so your procedure would become something like:

-- 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;
/

You may wish to add an additional predicate along the lines of:

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

to the update statement, so that if the values passed in are the same as the current values for the column, no update actually happens (it would be a waste of time).

Sign up to request clarification or add additional context in comments.

1 Comment

That's a really god point! I didn't think about these functions. I guess, I will rewrite my function. Thanks )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.