هل هناك طرق بديلة قائلا 'التالي' في pl/sql عن الحلقة ؟
سؤال
حتى لقد حصلت لحلقة أن عمليات قائمة من معرفات وبعض معقدة إلى حد ما من الأشياء للقيام به.دون الخوض في كل قبيح التفاصيل, أساسا هذا:
DECLARE l_selected APEX_APPLICATION_GLOBAL.VC_ARR2; ...snip... BEGIN -- get the list ids l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST); -- process each in a nice loop FOR i IN 1..l_selected.count LOOP -- do some data checking stuff... -- here we will look for duplicate entries, so we can noop if duplicate is found BEGIN SELECT county_id INTO v_dup_check FROM org_county_accountable WHERE organization_id = :P4_ID AND county_id = v_county_id; -- NEXT;! NOOP;! but there is no next! EXCEPTION WHEN NO_DATA_FOUND THEN dbms_output.put_line('no dups found, proceeding'); END; -- here we have code we only want to execute if there are no dupes already IF v_dup_check IS NULL THEN -- if not a duplicate record, proceed... ELSE -- reset duplicate check variable v_dup_check := NULL; END; END LOOP; END;
كيف يتعامل عادة مع هذا من خلال اختيار في قيمة ثم التفاف التعليمات البرمجية التالية في جملة IF التحقق للتأكد من أن تكرار التحقق من متغير باطل.لكنه مزعج.أنا فقط أريد أن أكون قادرا على القول المقبل ؛ أو NOOP;أو شيء من هذا.خصوصا أنني بالفعل للقبض على NO_DATA_FOUND استثناء.أعتقد أنني يمكن أن يكتب رسالة إلى Oracle, ولكن أنا الغريب كيف الآخرين التعامل مع هذا.
ويمكن أيضا لف هذا في وظيفة أيضا ولكن كنت أبحث عن شيء قليلا أكثر نظافة/أبسط.
المحلول
لحساب عدد الصفوف من الممكن أيضا (انظر Pourquoi Litytestdata) ولكن يمكنك أيضا أن تفعل ما تريد القيام به في كتلة when_no_data_found exception
.
declare
l_selected apex_application_global.vc_arr2;
l_county_id org_county_accountable.count_id%type;
begin
l_selected := apex_util.string_to_table(:p4_select_lst);
for i in l_selected.first..l_selected.last loop
begin
select count_id
into l_county_id
from org_county_accountable
where organization_id = :p4_id
and county_id = v_county_id;
exception
when no_data_found then
-- here we have code we only want to execute if there are no dupes already
-- if not a duplicate record, proceed...
end;
end loop;
end;
نصائح أخرى
أوراكل 11g يضيف ج-أسلوب "تواصل" حلقة بناء على تعليمات PL/SQL التي نحويا يبدو ما تبحث عنه.
لأغراض الخاصة بك, لماذا لا مجرد إزالة التكرارات قبل الدخول في الحلقة ؟ ويمكن أن يتم ذلك عن طريق الاستعلام l_selected باستخدام وظيفة الطاولة ، ثم تصفية السجلات كنت لا تريد بدلا من بالتكرار على كل القيمة.شيء من هذا القبيل...
declare
l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;
cursor no_dups_cur (p_selected APEX_APPLICATION_GLOBAL.VC_ARR2) is
select * from (
select selected.*,
count(*) over (partition by county_id) cnt -- analytic to find counts grouped by county_id
from table(p_selected) selected -- use table function to treat VC_ARR2 like a table
) where cnt = 1 -- remove records that have duplicate county_ids
;
begin
l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
for i in no_dups_cur(l_selected) loop
null; -- do whatever to non-duplicates
end loop;
end;
مجرد استبدال المنطق لتحديد "مكررة" مع الخاصة بك (لم يكن لديك ما يكفي من معلومات من المثال الخاص بك حقا الإجابة على هذا الجزء)
وبدلا من اصطياد NO_DATA_FOUND
، عن كيفية اختيار عدد الإدخالات مطابقة إلى متغير، ويقول l_count
، والشروع إذا كان هذا العدد يعمل بها أن يكون صفرا؟ شيء كما يلي:
DECLARE l_selected APEX_APPLICATION_GLOBAL.VC_ARR2; l_count INTEGER; ...snip... BEGIN -- get the list ids l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST); -- process each in a nice loop FOR i IN 1..l_selected.count LOOP -- do some data checking stuff... -- here we will count duplicate entries, so we can noop if duplicate is found SELECT COUNT(*) INTO l_count FROM org_county_accountable WHERE organization_id = :P4_ID AND county_id = v_county_id; IF l_count = 0 THEN -- here we have code we only want to execute if there are no dupes already -- if not a duplicate record, proceed... END IF; END LOOP; END;
<xmp>
<<next_loop>>
loop
...
...
if ....
then
goto next_loop;
</xmp>
وهذه هي الحالة التي يكون فيها بيان GOTO <م> قد م> أن تكون مفيدة. رؤية rel="nofollow أوراكل الوثائق في هياكل المراقبة لمعرفة كيفية القيام بذلك. أيضا، قد ترغب في البحث هنا لمعرفة كيفية الاستعلام عن وجود رقما قياسيا. تشغيل استعلام وانتظار استثناء ليس الأمثل.
وهناك طريقة أخرى - تحويل الاختيار إلى وظيفة المحلية:
DECLARE
l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;
...snip...
FUNCTION dup_exists
( p_org_id org_county_accountable.organization_id%TYPE
, p_county_id org_county_accountable.county_id%TYPE
) RETURN BOOLEAN
IS
v_dup_check org_county_accountable.county_id%TYPE;
BEGIN
SELECT county_id INTO v_dup_check FROM org_county_accountable
WHERE organization_id = p_org_id AND county_id = p_county_id;
RETURN TRUE;
EXCEPTION WHEN NO_DATA_FOUND THEN
RETURN FALSE;
END;
BEGIN
-- get the list ids
l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
-- process each in a nice loop
FOR i IN 1..l_selected.count
LOOP
-- do some data checking stuff...
-- here we have code we only want to execute if there are no dupes already
IF NOT dup_exists (:P4_ID, v_county_id) THEN
-- if not a duplicate record, proceed...
END;
END LOOP;
END;
وبطبيعة الحال، فإن وظيفة محلية يمكن إعادة كتابتها لاستخدام أسلوب العد إذا كنت تفضل ذلك:
FUNCTION dup_exists
( p_org_id org_county_accountable.organization_id%TYPE
, p_county_id org_county_accountable.county_id%TYPE
) RETURN BOOLEAN
IS
l_count INTEGER;
BEGIN
SELECT COUNT(*) INTO l_count
FROM org_county_accountable
WHERE organization_id = p_org_id AND county_id = p_county_id;
RETURN (l_count > 0);
END;
وأسلوب آخر هو لرفع والتعامل مع استثناء المعرفة من قبل المستخدم:
DECLARE
l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;
duplicate_org_county EXCEPTION;
...snip...
BEGIN
-- get the list ids
l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
-- process each in a nice loop
FOR i IN 1..l_selected.count
LOOP
BEGIN
-- do some data checking stuff...
-- here we will look for duplicate entries, so we can noop if duplicate is found
BEGIN
SELECT county_id INTO v_dup_check FROM org_county_accountable
WHERE organization_id = :P4_ID AND county_id = v_county_id;
RAISE duplicate_org_county;
EXCEPTION WHEN NO_DATA_FOUND THEN
dbms_output.put_line('no dups found, proceeding');
END;
-- here we have code we only want to execute if there are no dupes already
EXCEPTION
WHEN duplicate_org_county THEN NULL;
END;
END LOOP;
END;
وأنا لن تفعل عادة هذا، ولكن إذا كان هناك نصف دزينة من الأسباب للانتقال إلى السجل التالي، وهذا قد يكون من الأفضل أن الاتحادات الدولية المتداخلة متعددة.
وأنا أعلم أن هذا هو عدو السحالي ولكن أنا لا يمكن أن تساعد احظت أن أيا من الإجابات اتخاذ أعلاه في حساب المؤشر <لأ href = "http://docstore.mik.ua/orelly/oracle/langpkt/ch01_09. هتم "يختلط =" نوفولو "> سمات :
وهناك أربع سمات المرتبطة المؤشرات: ISOPEN، وجدت، NOTFOUND، وROWCOUNT. هذه الصفات يمكن الوصول إليها مع٪ المحدد للحصول على معلومات حول وضع المؤشر.
وبناء الجملة من أجل سمة المؤشر:
cursor_name%attribute
وحيث cursor_name هو اسم المؤشر واضح.
وحتى في هذه الحالة يمكنك استخدام ROWCOUNT (الذي يشير إلى عدد الصفوف جلب حتى الآن) لأغراضك، مثل هذا:
declare
aux number(10) := 0;
CURSOR cursor_name is select * from table where something;
begin
select count(*) into aux from table where something;
FOR row IN cursor_name LOOP
IF(aux > cursor_name%ROWCOUNT) THEN 'do something is not over';
ELSE 'do something else';
END IF;
END LOOP;
end;