【问题标题】:Column moving in Oracle Pl/Sql with for loop使用 for 循环在 Oracle Pl/Sql 中移动的列
【发布时间】:2019-05-15 07:21:45
【问题描述】:

例如,我想将我的 2 列在 KW_01(下拉)和 KW_03(下拉)之间移动到 KW_04(下拉)和 KW_06(下拉)之间。我在一个表中有 53 列。我写了代码(见下文),但不幸的是它不能正常工作。当我开始编写代码时,他会这样做。

意外结果:

Outer Loop counter is kw_04 Inner Loop counter is 1
Outer Loop counter is kw_04 Inner Loop counter is 2
Outer Loop counter is kw_04 Inner Loop counter is 3
Outer Loop counter is kw_05 Inner Loop counter is 1
Outer Loop counter is kw_05 Inner Loop counter is 2
Outer Loop counter is kw_05 Inner Loop counter is 3
Outer Loop counter is kw_06 Inner Loop counter is 1
Outer Loop counter is kw_06 Inner Loop counter is 2
Outer Loop counter is kw_06 Inner Loop counter is 3


DECLARE 
  plsql VARCHAR2(500);
BEGIN
  For i in (SELECT column_id
              FROM alsi_bedarfsplanung unpivot(column_value FOR column_id IN("KW_01", "KW_02", "KW_03", "KW_04", "KW_05", "KW_06"))
             WHERE column_id BETWEEN :drp1 AND :drp2
               and id = 1)
  LOOP
    FOR o in (SELECT column_value
                FROM alsi_bedarfsplanung unpivot(column_value FOR column_id IN("KW_01", "KW_02", "KW_03", "KW_04", "KW_05", "KW_06"))
               WHERE column_id BETWEEN :drp3 AND :drp4
                 and id = 1)
    LOOP
      plsql := ' UPDATE ALSI_BEDARFSPLANUNG SET ' || i.column_id || ' = ' ||
               o.column_value || ' where ID = 1 ';
      EXECUTE IMMEDIATE plsql;
    END LOOP;
  END LOOP;
END;

My DB

我想要什么,

Outer Loop counter is kw_04 Inner Loop counter is 1//(KW_1 Value)
Outer Loop counter is kw_05 Inner Loop counter is 2//(KW_2 Value)
Outer Loop counter is kw_06 Inner Loop counter is 3//(KW_3 Value)

【问题讨论】:

    标签: sql oracle plsql oracle11g


    【解决方案1】:

    问题在于您在循环中循环的方式;您实际需要做的是分别确定要更新的列和从列更新,然后遍历每组列进行更新。

    更好的是在一次更新中完成所有工作,如下所示:

    -- should error with "Invalid columns specified" due to final proc call,
    -- but should update the two rows accordingly
    DECLARE
      TYPE col_array IS TABLE OF VARCHAR2(30) INDEX BY pls_INTEGER;
      v_cols_to_update_arry col_array;
      v_cols_update_from_arry col_array;
      PROCEDURE update_cols (p_id IN INTEGER,
                             p_drp1 IN VARCHAR2,
                             p_drp2 IN VARCHAR2,
                             p_drp3 IN VARCHAR2,
                             p_drp4 IN VARCHAR2)
      IS
        v_sql CLOB := 'UPDATE alsi_bedarfsplanung SET '||CHR(10);
      BEGIN
        SELECT column_id
        BULK COLLECT INTO v_cols_to_update_arry
        FROM   alsi_bedarfsplanung
        UNPIVOT (column_val FOR column_id IN (kw_01, kw_02, kw_03, kw_04, kw_05, kw_06, kw_07, kw_08))
        WHERE  column_id BETWEEN p_drp1 AND p_drp2
        AND    id = p_id;
    
        SELECT column_id
        BULK COLLECT INTO v_cols_update_from_arry
        FROM   alsi_bedarfsplanung
        UNPIVOT (column_val FOR column_id IN (kw_01, kw_02, kw_03, kw_04, kw_05, kw_06, kw_07, kw_08))
        WHERE  column_id BETWEEN p_drp3 AND p_drp4
        AND    id = p_id;
    
        IF v_cols_to_update_arry.count > 0
           AND v_cols_update_from_arry.count > 0
           AND v_cols_to_update_arry.count = v_cols_update_from_arry.count THEN
    
          FOR i IN 1..v_cols_to_update_arry.count
          LOOP
            if i = 1 then 
              v_sql := v_sql || '  ' || v_cols_to_update_arry(i) || ' = ' || v_cols_update_from_arry(i);
            else
              v_sql := v_sql || ',' || CHR(10) || '  ' || v_cols_to_update_arry(i) || ' = ' || v_cols_update_from_arry(i);
            end if;
          END LOOP;
    
          v_sql := v_sql || chr(10) || 'where id = :p_id';
    
          EXECUTE IMMEDIATE v_sql USING p_id;
    
        ELSE
          raise_application_error(-20001, 'Invalid columns specified');
        END IF;
      END update_cols;
    BEGIN
      update_cols (p_id => 1,
                   p_drp1 => 'KW_04',
                   p_drp2 => 'KW_06',
                   p_drp3 => 'KW_01',
                   p_drp4 => 'KW_03');
    
      COMMIT;
    
      update_cols (p_id => 2,
                   p_drp1 => 'KW_05',
                   p_drp2 => 'KW_08',
                   p_drp3 => 'KW_01',
                   p_drp4 => 'KW_04');
    
      COMMIT;
    
      update_cols (p_id => 1,
                   p_drp1 => 'KW_01',
                   p_drp2 => 'KW_02',
                   p_drp3 => 'KW_05',
                   p_drp4 => 'KW_05');
    
    END;
    /
    

    这通过将每个列列表获取到一个单独的数组中,在数组上循环以构建正在更新的列列表,然后将其连接到更新语句中。

    Here's a demo of it working

    【讨论】:

    • 如果要定期运行,请在我的答案中使用匿名块内的过程并将其创建为适当的过程(最好在包内)。
    猜你喜欢
    • 2016-08-03
    • 2013-07-21
    • 2019-07-08
    • 2010-10-21
    • 1970-01-01
    • 2017-07-04
    • 2022-08-14
    • 2021-07-07
    • 2020-12-04
    相关资源
    最近更新 更多