هل هناك طرق بديلة قائلا 'التالي' في pl/sql عن الحلقة ؟

StackOverflow https://stackoverflow.com/questions/429508

سؤال

حتى لقد حصلت لحلقة أن عمليات قائمة من معرفات وبعض معقدة إلى حد ما من الأشياء للقيام به.دون الخوض في كل قبيح التفاصيل, أساسا هذا:

    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;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top