检查表[pl / sql block]中是否存在行的正确方法

时间:2014-01-15 15:03:23

标签: sql oracle select plsql

昨天我正在编写一些任务,让我感到震惊的是,当我使用pl / sql时,我真的不知道正确和接受的方式检查表中是否存在行。

例如,让我们使用表

PERSON(ID, Name); 

显然我做不到(除非有一些秘密方法)类似于:

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

所以解决问题的标准方法是:

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; 

但是我不知道这是否是可接受的方式,或者如果有更好的检查方式,如果有人可以与我分享他们的智慧,我真的会感到高兴:)

干杯。

8 个答案:

答案 0 :(得分:57)

我不会将常规代码推送到异常块中。只需检查是否存在符合条件的行,然后从那里继续:

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;

答案 1 :(得分:7)

带有独立SELECT的IMO代码,用于检查表中是否存在行,但没有充分利用数据库。在你的例子中,你有一个硬编码的ID值,但这不是应用程序在“现实世界”中的工作方式(至少不在我的世界 - 你的可能会有所不同:-)。在典型的应用程序中,您将使用光标查找数据 - 所以假设您有一个正在查看发票数据的应用程序,并且需要知道客户是否存在。应用程序的主体可能类似于

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

并在-- do something here中找到客户是否存在,如果没有打印错误消息。

这样做的一种方法是输入某种单身SELECT,如

-- 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相对缓慢且容易出错。 IMO更好的方法(tm)是将它合并到主光标中:

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;

此代码依据PERSON.ID被声明为PERSON上的PRIMARY KEY(或至少为NOT NULL);逻辑是,如果PERSON表外部连接到查询,并且PERSON_ID出现为NULL,则意味着在PERSON中找不到给定CUSTOMER_ID的行,因为PERSON.ID必须具有值(即至少为NOT NULL)。

分享并享受。

答案 2 :(得分:5)

为这只猫皮肤涂抹的方法很多。我在每个表的包中放了一个简单的函数......

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;

让你的支票真的很干净......

IF pkg.exists(someId) THEN
...
ELSE
...
END IF;

答案 3 :(得分:4)

select nvl(max(1), 0) from mytable;

如果没有行,则此语句产生0,如果该表中至少有一行,则产生1。它比选择计数(*)更快。优化器&#34;看到&#34;只需要提取一行来回答问题。

这是一个(详细的)小例子:

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 :(得分:0)

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);

答案 5 :(得分:0)

如果您使用的是显式游标,则应如下所示。

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;

答案 6 :(得分:0)

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

不遍历所有记录。

如果 MY_TABLE 没有数据,则 my_if_has_data 设置为空。

答案 7 :(得分:0)

您可以在Oracle PL / SQL中执行EXISTS

您可以执行以下操作:

DECLARE
    n_rowExist NUMBER := 0;
BEGIN
    SELECT CASE WHEN EXISTS (
      SELECT 1
      FROM person
      WHERE ID = 10
    ) THEN 1 ELSE 0 INTO n_rowExist END FROM DUAL;
    
    IF n_rowExist = 1 THEN
       -- do things when it exists
    ELSE
       -- do things when it doesn't exist
    END IF;

END;
/

说明:

在嵌套的查询中,它以SELECT CASE WHEN EXISTS开头,并在括号(SELECT 1 FROM person WHERE ID = 10)之后,如果找到ID为10的人,它将返回一个结果。如果查询中有结果,则它将为1分配值,否则将为n_rowExist变量分配0值。然后,if语句检查返回的值是否等于1,然后返回true,否则返回0 = 1,并且返回false。