动态更新数据库列的数据库过程

时间:2019-01-29 09:42:43

标签: sql oracle stored-procedures plsql dynamic-sql

要求是仅在db列中更新从前端编辑的那些列。 我正在使用的逻辑是从Java代码向DB过程发送2个数组。

第一个数组是:Column_array,其中包含必须更新的列名。

第二个数组:value_array,其中包含表示column_array的列的值。

来自JAVA:

Array value_array = ((OracleConnection) dbConnection).createOracleArray("STRING_ARRAY",
                valueList.toArray());

        Array param_array = ((OracleConnection) dbConnection).createOracleArray("STRING_ARRAY",
                            paramList.toArray());

 stmt = dbConnection.prepareCall(SqlConstants.UPDATE_SUBSCRIBER_CONFIG_IN_BOLTES);//
            stmt.setLong(1, 3628);
            stmt.setLong(2, 3629);
            stmt.setLong(3, 3632);
            stmt.setArray(4, param_array);
            stmt.setArray(5, value_array);
            int count = stmt.executeUpdate();

现在在数据库端:

我该如何遍历此列表以更新并在SET子句中设置它??

 PROCEDURE update_subscriber_config (
    p_app_id        VARCHAR2,
    p_service_id     VARCHAR2,
    p_pubsub_id       VARCHAR2,
    column_list     string_array,
    value_list      string_array
)
    AS
BEGIN

FOR a IN 1..column_list.count LOOP
        update  bolt_oracle_pubsub_config set 
            column_list(a)=value_list(a),
             ...how to do iteration here???

      where  APP_ID = p_app_id AND SERVICE_ID =  p_service_id AND PUBSUB_ID = p_pubsub_id;
       END LOOP;

END update_subscriber_config;

请帮助。

3 个答案:

答案 0 :(得分:2)

我找到了比数组迭代更简单的解决方案。

解决方法是使用COALESCE方法。

 PROCEDURE TEST (
      p_app_id       NUMBER,
    p_service_id   NUMBER,
    p_pubsub_id    NUMBER,
    p_pubsub_name       VARCHAR2,
    p_host              VARCHAR2,
    p_user_name           VARCHAR2,
    p_auth_key              VARCHAR2
)
    AS
BEGIN

     update bolt_elastic_pubsub_config set 
      PUBSUB_NAME = coalesce(p_pubsub_name, PUBSUB_NAME),
       HOST = coalesce(p_host, HOST),
        USER_NAME = coalesce(p_user_name, USER_NAME),
        AUTH_KEY = coalesce(p_auth_key, AUTH_KEY)
     where  APP_ID = p_app_id AND SERVICE_ID =  p_service_id AND PUBSUB_ID = p_pubsub_id;

END TEST;

答案 1 :(得分:0)

您必须使用动态SQL来组装定制的更新语句。看起来像这样:

PROCEDURE update_subscriber_config (
    p_app_id        VARCHAR2,
    p_service_id     VARCHAR2,
    p_pubsub_id       VARCHAR2,
    column_list     string_array,
    value_list      string_array
)
AS
   stmt varchar2(32767);
BEGIN

    stmt := 'update  bolt_oracle_pubsub_config set ';

    FOR a IN 1..column_list.count LOOP
        if a != 1 then
           stmt := stmt ||', ';
        end if;
        stmt := stmt || column_list(a) ||'=''' ||value_list(a)||'''';
       END LOOP;

       stmt := stmt ||
             ' where  APP_ID = :p1 AND SERVICE_ID = :p2 AND PUBSUB_ID = :p3';
      execute immediate stmt using p_app_id , p_service_id , p_pubsub_id;
END update_subscriber_config;

这是一个非常粗糙的实现,因为它假定所有传递的列都可以视为字符串。如果表中包含数字或日期列,则应考虑处理数据转换,因为这可能会成为问题。

动态SQL很难,因为它将编译错误转换为运行时错误。在您的情况下,您有一段代码可能会在每次调用它时执行不同的更新语句。因此,测试此过程是一个噩梦。这意味着您非常依赖具有有效内容的前端传递数组。

答案 2 :(得分:0)

也许您可以尝试避免使用作为列数组的数组之一,因为如果值为null,则Oracle SQL可以容忍。

下面是伪代码。

TSprite

如果更新SQL中声明的任何列为空,则执行更新后表中的列将为null或为空。话虽如此,请确保已填充所有destructor TSprite.Destroy; begin Down.Free; Right.Free; inherited; end; 或必填列。

我想避免由于容易出错而导致动态SQL更新。如果在不使用动态SQL的情况下获得结果,那么为什么要使用动态SQL来解决麻烦呢?