it-swarm.com.de

Richtige Methode zum Überprüfen, ob eine Zeile in der Tabelle existiert [pl/sql block]

Ich habe gestern einige Aufgaben geschrieben und es ist mir aufgefallen, dass ich DER RICHTIGE und AKZEPTIERTE Weg nicht wirklich weiß, ob eine Zeile in der Tabelle existiert, wenn ich pl/sql verwende.

Verwenden wir zum Beispiel die Tabelle

PERSON(ID, Name); 

Offensichtlich kann ich kann nicht (es sei denn, es gibt eine geheime Methode) so etwas wie:

BEGIN 
  IF EXISTS SELECT id FROM person WHERE ID = 10; 
    -- do things when exists
  ELSE
    -- do things when doesn't exist
  END IF;
END;

Meine Standardlösung war also:

DECLARE
  tmp NUMBER;
BEGIN 
  SELECT id INTO tmp FROM person WHERE id = 10; 
  --do things when record exists
EXCEPTION
  WHEN no_data_found THEN
  --do things when record doesn't exist
END; 

Allerdings weiß ich nicht, ob dies akzeptiert wird oder ob es eine bessere Möglichkeit gibt, dies zu überprüfen. Ich würde es wirklich begrüßen, wenn jemand seine Weisheit mit mir teilen könnte :)

Prost.

31
devBem

Ich würde regulären Code nicht in einen Ausnahmeblock verschieben. Prüfen Sie einfach, ob Zeilen vorhanden sind, die Ihrer Bedingung entsprechen, und fahren Sie mit dem Vorgang fort:

declare
  any_rows_found number;
begin
  select count(*)
  into   any_rows_found
  from   my_table
  where  rownum = 1 and
         ... other conditions ...

  if any_rows_found = 1 then
    ...
  else
    ...
  end if;
53
David Aldridge

IMO-Code mit einer eigenständigen SELECT-Anweisung, mit der überprüft wird, ob eine Zeile in einer Tabelle vorhanden ist, nutzt die Datenbank nicht ordnungsgemäß. In Ihrem Beispiel haben Sie einen fest codierten ID-Wert, aber so funktionieren Apps nicht in der "realen Welt" (zumindest nicht in my world - Ihre können anders sein :-). In einer typischen App verwenden Sie einen Cursor zum Suchen von Daten. Angenommen, Sie haben eine App, die Rechnungsdaten betrachtet, und müssen wissen, ob der Kunde vorhanden ist. Der Hauptteil der App könnte etwa so aussehen

FOR aRow IN (SELECT * FROM INVOICES WHERE DUE_DATE < TRUNC(SYSDATE)-60)
LOOP
  -- do something here
END LOOP;

und im -- do something here möchten Sie herausfinden, ob der Kunde existiert, und falls nicht, eine Fehlermeldung ausgeben.

Eine Möglichkeit, dies zu tun, besteht darin, eine Art Singleton SELECT wie in einzufügen

-- Check to see if the customer exists in PERSON

BEGIN
  SELECT 'TRUE'
    INTO strCustomer_exists
    FROM PERSON
    WHERE PERSON_ID = aRow.CUSTOMER_ID;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    strCustomer_exists := 'FALSE';
END;

IF strCustomer_exists = 'FALSE' THEN
  DBMS_OUTPUT.PUT_LINE('Customer does not exist!');
END IF;

iMO ist dies jedoch relativ langsam und fehleranfällig. IMO ein besserer Weg (tm), um dies zu tun, ist es, es in den Hauptcursor zu integrieren:

FOR aRow IN (SELECT i.*, p.ID AS PERSON_ID
               FROM INVOICES i
               LEFT OUTER JOIN PERSON p
                 ON (p.ID = i.CUSTOMER_PERSON_ID)
               WHERE DUE_DATA < TRUNC(SYSDATE)-60)
LOOP
  -- Check to see if the customer exists in PERSON

  IF aRow.PERSON_ID IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('Customer does not exist!');
  END IF;
END LOOP;

Dieser Code zählt, wenn PERSON.ID als PRIMARY KEY für PERSON deklariert ist (oder zumindest nicht NULL ist). Die Logik ist, dass, wenn die PERSON-Tabelle mit der Abfrage außerhalb verbunden ist und die PERSON_ID als NULL angegeben wird, keine Zeile in PERSON für die angegebene CUSTOMER_ID gefunden wurde, da PERSON.ID einen Wert haben muss (dh mindestens NOT ist.) NULL).

Teile und genieße.

7
Bob Jarvis

Viele Möglichkeiten, diese Katze zu enthäuten. Ich habe eine einfache Funktion in das Paket jeder Tabelle eingefügt ...

function exists( id_in in yourTable.id%type ) return boolean is
  res boolean := false;
begin
  for c1 in ( select 1 from yourTable where id = id_in and rownum = 1 ) loop
    res := true;
    exit; -- only care about one record, so exit.
  end loop;
  return( res );
end exists;

Macht Ihre Schecks wirklich sauber ...

IF pkg.exists(someId) THEN
...
ELSE
...
END IF;
5
gfrobenius
select nvl(max(1), 0) from mytable;

Diese Anweisung ergibt 0, wenn keine Zeilen vorhanden sind, 1, wenn mindestens eine Zeile in dieser Tabelle enthalten ist. Es ist viel schneller als eine Auswahlzählung (*). Der Optimierer "sieht", dass nur eine einzelne Zeile abgerufen werden muss, um die Frage zu beantworten.

Hier ist ein (ausführliches) kleines Beispiel:

declare
  YES constant      signtype := 1;
  NO  constant      signtype := 0;
  v_table_has_rows  signtype;
begin

  select nvl(max(YES), NO)
    into v_table_has_rows
    from mytable -- where ...
  ;

  if v_table_has_rows = YES then
    DBMS_OUTPUT.PUT_LINE ('mytable has at least one row');
  end if;

end;
4
Andreas Wismann
select max( 1 )
  into my_if_has_data
  from MY_TABLE    X
 where X.my_field   = my_condition
   and rownum       = 1;

Nicht alle Datensätze durchlaufen.

Wenn MY_TABLE keine Daten enthält, wird my_if_has_data auf null gesetzt.

0
Robert Tebiev

Wenn Sie einen expliziten Cursor verwenden, sollte es folgendermaßen aussehen.

DECLARE
   CURSOR get_id IS 
    SELECT id 
      FROM person 
      WHERE id = 10;

  id_value_ person.id%ROWTYPE;
BEGIN 
   OPEN get_id;
   FETCH get_id INTO id_value_;

   IF (get_id%FOUND) THEN
     DBMS_OUTPUT.PUT_LINE('Record Found.');
   ELSE
     DBMS_OUTPUT.PUT_LINE('Record Not Found.');
   END IF;
   CLOSE get_id;

EXCEPTION
  WHEN no_data_found THEN
  --do things when record doesn't exist
END;
0
Dinidu Hewage
Select 'YOU WILL SEE ME' as ANSWER from dual
where exists (select 1 from dual where 1 = 1);

Select 'YOU CAN NOT SEE ME' as ANSWER from dual
where exists (select 1 from dual where 1 = 0);

Select 'YOU WILL SEE ME, TOO' as ANSWER from dual
where not exists (select 1 from dual where 1 = 0);
0
Mohsen Heydari