【问题标题】:how to create dynamic variable name inside a for loop in sql如何在sql的for循环中创建动态变量名
【发布时间】:2015-09-10 10:36:47
【问题描述】:

我是 sql 新手。不是专家。我有一个过程,我需要使用一个键从两个表中提取一些值 表 ord_item 和 product_ext_data view_id 是关键。

我想从 product_ext_data 中提取 param_value 到变量 d_DestNumber1,d_DestNumber2 ...d_DestNumber10(预计最多 10 个值)

为此,我使用 for 循环遍历游标输出并将每个 param_value 分配给每个变量。 我不确定如何根据 for 循环中的 i 值动态创建变量名

               CREATE OR REPLACE PROCEDURE C1_REMOVEFNFDATA(v_soid                  VARCHAR2,
                    C1_REMOVEFNFDATA_cv IN OUT cv_types.customer_tp) IS

   l_count NUMBER := 0;
 d_DestNumber1 PRODUCT_EXT_DATA.param_value%TYPE;
 d_DestNumber2 PRODUCT_EXT_DATA.param_value%TYPE;
  d_DestNumber3 PRODUCT_EXT_DATA.param_value%TYPE;
 d_DestNumber4 PRODUCT_EXT_DATA.param_value%TYPE;
 d_DestNumber5 PRODUCT_EXT_DATA.param_value%TYPE;
 d_DestNumber6 PRODUCT_EXT_DATA.param_value%TYPE;
 d_DestNumber7 PRODUCT_EXT_DATA.param_value%TYPE;
 d_DestNumber8 PRODUCT_EXT_DATA.param_value%TYPE;
 d_DestNumber9 PRODUCT_EXT_DATA.param_value%TYPE;
d_DestNumber10 PRODUCT_EXT_DATA.param_value%TYPE;

    CURSOR c_dest_num IS
   SELECT P.VIEW_ID as view_id, P.param_value as destination_number
    FROM ORD_ITEM o, 
     PRODUCT_EXT_DATA p
    WHERE o.service_order_id = to_number(v_soid)
  AND O.ITEM_ACTION_ID IN (30) -- delete
  AND P.VIEW_ID          = O.VIEW_ID
  AND P.PARAM_ID         = 5100
  AND o.is_cancelled     = 0;
  d_dest_num c_dest_num%rowtype;

  BEGIN
   SELECT count(*) 
  INTO l_count
    FROM ORD_ITEM o, 
     PRODUCT_EXT_DATA p
  WHERE o.service_order_id = to_number(v_soid)
 AND o.member_type      = 10   -- product
 AND O.ITEM_ACTION_ID IN (30) -- delete
 AND P.VIEW_ID          = O.VIEW_ID
 AND P.PARAM_ID         = 5100
 AND o.is_cancelled     = 0;

    IF(l_count != 0) THEN

     OPEN c_dest_num;
   LOOP FETCH c_dest_num INTO d_dest_num;
   EXIT WHEN c_dest_num%NOTFOUND;

    for i in 1 .. l_count
   LOOP
   d_DestNumber+i := d_dest_num.destination_number;

   END LOOP;
   END LOOP;
   CLOSE c_dest_num;
   END IF;



  OPEN C1_REMOVEFNFDATA_CV FOR 
   SELECT l_count AS FnfRemoveCompCount,
    d_DestNumber1 AS DestNumber1,
    d_DestNumber2 AS DestNumber2,
    d_DestNumber3 AS DestNumber3,
    d_DestNumber4 AS DestNumber4,
    d_DestNumber5 AS DestNumber5,
    d_DestNumber6 AS DestNumber6,
    d_DestNumber7 AS DestNumber7,
    d_DestNumber8 AS DestNumber8,
    d_DestNumber9 AS DestNumber9,
    d_DestNumber10 AS DestNumber10,
    FROM DUAL;

   END;

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    您不能使用动态变量名。但是您可以使用集合(如 sblandin 所示;这是使用关联数组而不是可变数组,但想法相同):

    CREATE OR REPLACE PROCEDURE C1_REMOVEFNFDATA(v_soid VARCHAR2,
      C1_REMOVEFNFDATA_cv IN OUT cv_types.customer_tp)
    IS
      l_count NUMBER := 0;
      TYPE t_destnumbers IS TABLE OF PRODUCT_EXT_DATA.param_value%TYPE
        INDEX BY PLS_INTEGER;
      d_destnumber t_destnumbers;
    
      CURSOR c_dest_num IS
        SELECT P.VIEW_ID as view_id, P.param_value as destination_number
        FROM ORD_ITEM o
        JOIN PRODUCT_EXT_DATA p
        ON P.VIEW_ID = O.VIEW_ID
        WHERE o.service_order_id = to_number(v_soid)
        AND O.ITEM_ACTION_ID IN (30) -- delete
        AND P.PARAM_ID = 5100
        AND o.is_cancelled = 0;
    
      d_dest_num c_dest_num%rowtype;
    
    BEGIN
      SELECT count(*) 
      INTO l_count
      FROM ORD_ITEM o
      JOIN PRODUCT_EXT_DATA p
      ON P.VIEW_ID = O.VIEW_ID
      WHERE o.service_order_id = to_number(v_soid)
      AND o.member_type = 10 -- product
      AND O.ITEM_ACTION_ID IN (30) -- delete
      AND P.PARAM_ID = 5100
      AND o.is_cancelled = 0;
    
      IF(l_count != 0) THEN
         OPEN c_dest_num;
         LOOP
           FETCH c_dest_num INTO d_dest_num;
           EXIT WHEN c_dest_num%NOTFOUND;
           FOR i IN 1 .. l_count
           LOOP
             d_DestNumber(i) := d_dest_num.destination_number;
           END LOOP;
        END LOOP;
        CLOSE c_dest_num;
      END IF;
    
      -- populate the required nuimber of entries with null
      FOR i IN l_count + 1 .. 10 LOOP
        d_DestNumber(i) := null;
      END LOOP;
    
      OPEN C1_REMOVEFNFDATA_CV FOR 
        SELECT l_count AS FnfRemoveCompCount,
        d_DestNumber(1) AS DestNumber1,
        d_DestNumber(2) AS DestNumber2,
        d_DestNumber(3) AS DestNumber3,
        d_DestNumber(4) AS DestNumber4,
        d_DestNumber(5) AS DestNumber5,
        d_DestNumber(6) AS DestNumber6,
        d_DestNumber(7) AS DestNumber7,
        d_DestNumber(8) AS DestNumber8,
        d_DestNumber(9) AS DestNumber9,
        d_DestNumber(10) AS DestNumber10
        FROM DUAL;
    END;
    /
    

    我不认为这是你想要的东西;看到的最后一个参数值被复制到每个 l_count 变量中,所以如果你实际上有三个值 - 比如说 P1、P3、P2 并且碰巧按该顺序检索它们 - 那么你会看到:

    FNFREMOVECOMPCOUNT                      DESTNUMBER1                      DESTNUMBER2                      DESTNUMBER3                      DESTNUMBER4                      DESTNUMBER5                      DESTNUMBER6                      DESTNUMBER7                      DESTNUMBER8                      DESTNUMBER9                      DESTNUMBER10                     
    --------------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- 
    3                                       P2                               P2                               P2                                                                                                                                                                                                                                                                      
    

    您可能希望在光标循环内增加l_count。这使用了一个更简单的结构,并取消了初始计数查询:

    CREATE OR REPLACE PROCEDURE C1_REMOVEFNFDATA(v_soid VARCHAR2,
      C1_REMOVEFNFDATA_cv IN OUT cv_types.customer_tp)
    IS
      l_count NUMBER := 0;
      TYPE t_destnumbers IS TABLE OF PRODUCT_EXT_DATA.param_value%TYPE
        INDEX BY PLS_INTEGER;
      d_destnumber t_destnumbers;
    BEGIN
      FOR d_dest_num IN (
        SELECT P.VIEW_ID as view_id, P.param_value as destination_number
        FROM ORD_ITEM o
        JOIN PRODUCT_EXT_DATA p
        ON P.VIEW_ID = O.VIEW_ID
        WHERE o.service_order_id = to_number(v_soid)
        AND o.member_type = 10 -- product
        AND O.ITEM_ACTION_ID = 30 -- delete
        AND P.PARAM_ID = 5100
        AND o.is_cancelled = 0
      )
      LOOP
        l_count := l_count + 1;
        d_DestNumber(l_count) := d_dest_num.destination_number;
      END LOOP;
    
      -- populate the required nuimber of entries with null
      FOR i IN l_count + 1 .. 10 LOOP
        d_DestNumber(i) := null;
      END LOOP;
    
      OPEN C1_REMOVEFNFDATA_CV FOR 
        SELECT l_count AS FnfRemoveCompCount,
        d_DestNumber(1) AS DestNumber1,
        d_DestNumber(2) AS DestNumber2,
        d_DestNumber(3) AS DestNumber3,
        d_DestNumber(4) AS DestNumber4,
        d_DestNumber(5) AS DestNumber5,
        d_DestNumber(6) AS DestNumber6,
        d_DestNumber(7) AS DestNumber7,
        d_DestNumber(8) AS DestNumber8,
        d_DestNumber(9) AS DestNumber9,
        d_DestNumber(10) AS DestNumber10
        FROM DUAL;
    END;
    /
    

    使用相同的数据获得:

    FNFREMOVECOMPCOUNT                      DESTNUMBER1                      DESTNUMBER2                      DESTNUMBER3                      DESTNUMBER4                      DESTNUMBER5                      DESTNUMBER6                      DESTNUMBER7                      DESTNUMBER8                      DESTNUMBER9                      DESTNUMBER10                     
    --------------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- 
    3                                       P1                               P3                               P2                                                                                                                                                                                                                                                                      
    

    不过,如果我理解它的正确操作,您不需要过程或游标循环;您可以使用纯 SQL 和数据透视:

    SELECT * FROM (
      SELECT COUNT(*) OVER (PARTITION BY P.VIEW_ID) as FNFREMOVECOMPCOUNT,
        P.param_value as destination_number,
        ROW_NUMBER() OVER (PARTITION BY P.VIEW_ID ORDER BY null) AS rn
      FROM ORD_ITEM o
      JOIN PRODUCT_EXT_DATA p
      ON P.VIEW_ID = O.VIEW_ID
      WHERE o.service_order_id = to_number(:v_soid)
      AND o.member_type = 10 -- product
      AND O.ITEM_ACTION_ID = 30 -- delete
      AND P.PARAM_ID = 5100
      AND o.is_cancelled = 0
    )
    PIVOT (MAX(destination_number) AS destnumber
      FOR (rn) IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    

    这会根据行号添加一个 rn 列,该列将是 1 到 10(最多),然后用于枢轴 IN 子句。并且它增加了一个分析计数来获得相当于过程的l_count。得到相同的结果:

    FNFREMOVECOMPCOUNT 1_DESTNUMBER 2_DESTNUMBER 3_DESTNUMBER 4_DESTNUMBER 5_DESTNUMBER 6_DESTNUMBER 7_DESTNUMBER 8_DESTNUMBER 9_DESTNUMBER 10_DESTNUMBE
    ------------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------
                     3 P1           P2           P3                                                                                                     
    

    SQL Fiddle

    【讨论】:

      【解决方案2】:

      您可以使用数组而不是多个变量。在你的声明部分写:

        type DestNumber is varray(10) of PRODUCT_EXT_DATA.param_value%TYPE;
        --Initializes the array
        d_DestNumber DestNumber := DestNumber(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      

      然后在您的FOR ... LOOP 中您可以使用:

      d_DestNumber(i) := d_dest_num.destination_number;
      

      我不完全理解 d_DestNumbers 在最终光标中的使用,但我希望你能利用我的回答 ;-)

      你可以在这个问题中找到很多关于数组的有用信息:Oracle PL/SQL - How to create a simple array variable?

      【讨论】:

      • @sbladin:谢谢。它达到了我的目的:-)
      猜你喜欢
      • 2018-08-20
      • 1970-01-01
      • 2019-06-14
      • 2011-09-15
      • 2012-01-05
      • 2021-04-06
      • 2015-03-06
      • 2019-10-04
      • 2014-05-20
      相关资源
      最近更新 更多