Frage

So eine habe ich für Schleife bekam, die eine Liste von IDs verarbeitet und hat einige ziemlich komplexe Dinge zu tun. Ohne auf alle die hässlichen Details, im Grunde diese:

    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;

Wie ich normalerweise umgehen dies, indem sie in einen Wert auswählen und dann den folgenden Code in einer IF-Anweisung wickelt Überprüfung, um sicherzustellen, dass doppelte Kontrolle Variable NULL ist. Aber es ist ärgerlich. Ich möchte nur in der Lage sein, als nächstes zu sagen; oder NOOP; oder so. Vor allem, da muss ich schon die NO_DATA_FOUND Ausnahme fangen. Ich glaube, ich könnte einen Brief an Oracle schreiben, aber ich bin neugierig, wie andere damit umgehen.

Ich könnte auch in einer Funktion wickle dies auch, aber ich war auf der Suche nach etwas ein wenig sauberen / einfacher.

War es hilfreich?

Lösung

Um die Anzahl der Zeilen ist ebenfalls möglich (siehe Pourquoi Litytestdata) zu zählen, aber Sie können auch tun, was Sie in dem when_no_data_found exception Block tun wollen.

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;

Andere Tipps

Oracle 11g fügt ein C-Stil „weiter“ Schleife zu PL / SQL-Konstrukt, das syntaktisch klingt wie das, was Sie suchen.

Für Ihre Zwecke, warum beseitigen nicht nur die Duplikate, bevor die Schleife eintritt? Dies könnte geschehen durch abfragt l_selected eine Tabellenfunktion verwenden, und dann Datensätze herausgefiltert werden Sie nicht wollen, statt iterieren alle Wert. So etwas wie ...

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;

Nur die Logik ersetzen für die Bestimmung eines „Duplikat“ mit Ihrem eigenen (nicht genügend Informationen aus Ihrem Beispiel hat wirklich, dass ein Teil zu beantworten)

Stattdessen fängt NO_DATA_FOUND, wie etwa die Anzahl der passenden Einträge in eine Variable Auswählen, sagt l_count und fortfahren, wenn diese Zählung Null sein klappt? Etwas wie folgt aus:

    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>

Dies ist ein Fall, in dem eine GOTO-Anweisung könnte nützlich sein. Sehen Sie sich die Oracle Dokumentation in der Kontrollstrukturen zu sehen, wie dies zu tun. Außerdem können Sie hier in der Nähe suchen, um herauszufinden, wie die Existenz eines Datensatzes abfragen. eine Abfrage und wartet auf eine Ausnahme läuft nicht optimal ist.

Eine andere Art und Weise - drehen Sie den Scheck in eine lokale Funktion:

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;

Natürlich könnte die lokale Funktion neu geschrieben werden, um die Zählmethode zu verwenden, wenn Sie bevorzugen:

  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;

Eine andere Methode ist eine benutzerdefinierte Ausnahme zu heben und zu behandeln:

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;

Ich würde dies normalerweise nicht tun, aber wenn es ein halbes Dutzend Gründe dafür waren zum nächsten Datensatz zu springen, kann dies auf mehrere verschachtelte IFs vorzuziehen.

Ich weiß, dass dies ein Oldie, aber ich konnte nicht helfen, dass keine der Antworten bemerken oben in Betracht ziehen Sie den Cursor Attribute :

Es gibt vier Attribute mit Cursor zugeordnet: ISOPEN, GEFUNDEN, NOTFOUND und ROWCOUNT. Diese Attribute können mit dem% delimiter zugegriffen werden, um Informationen über den Zustand des Cursors zu erhalten.

Die Syntax für ein Cursor-Attribut ist:

cursor_name%attribute

wo cursor_name ist der Name des expliziten Cursor.

Also in diesem Fall könnten Sie ROWCOUNT (die die Anzahl der Zeilen angibt, so weit hergeholt) für Ihre Zwecke, wie folgt aus:

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;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top