我是sql的新手。不是专家。我有一个proc,我需要使用一个键从两个表中提取一些值 表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;
答案 0 :(得分:2)
您无法拥有动态变量名称。但你可以使用一个集合(如sblandin所示;这是使用关联数组而不是varray但是相同的想法):
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(最多),然后用于pivot 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
答案 1 :(得分:1)
您可以使用数组而不是多个变量。在你的声明部分写:
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?