检查记录是否已存在于数据库中[关闭]

问题描述 投票:0回答:3

检查记录是否已存在于数据库中的最快方法是什么。我没有唯一的身份证。可以在值之后检查名称,姓氏,出生日期

sql oracle plsql
3个回答
2
投票

通常,检查行是否存在的最快方法是使用SELECT-INTO(隐式游标)语句,而不是显式游标。找到行时,它始终更快。当找不到行时,SELECT-INTO引发NO_DATA_FOUND并且异常处理相对较慢。

因此,当您编写代码时,请考虑上下文,考虑数据和使用模式。您是否希望查询通常能找到一行?然后选择SELECT-INTO。你认为通常获取会失败吗?然后使用显式游标。

当然,正如@Randy所指出的,您需要确保拥有正确的索引以确保优化查找。

关于这个主题,我的blog post应该有助于填写详细信息,并为您提供一些代码来对付这些想法。但我也会在这里发帖以使其更容易。

CREATE OR REPLACE PACKAGE tmr 
IS 
   PROCEDURE start_timer; 

   PROCEDURE show_elapsed (str IN VARCHAR2); 
END tmr; 
/

CREATE OR REPLACE PACKAGE BODY tmr 
IS 
   last_timing   NUMBER := NULL; 

   PROCEDURE start_timer 
   IS 
   BEGIN 
      last_timing := DBMS_UTILITY.get_time; 
   END; 

   PROCEDURE show_elapsed (str IN VARCHAR2) 
   IS 
   BEGIN 
      DBMS_OUTPUT.put_line ( 
            str 
         || ': ' 
         || MOD (DBMS_UTILITY.get_time - last_timing + POWER (2, 32), 
                 POWER (2, 32))); 
      start_timer; 
   END; 
END tmr; 
/

CREATE TABLE not_much_stuff (n NUMBER)
;

INSERT INTO not_much_stuff
       SELECT LEVEL
         FROM DUAL
   CONNECT BY LEVEL < 11
;

-- Demonstration of Exception Behavior with SELECT-INTO
DECLARE 
   my_n   not_much_stuff.n%TYPE; 
BEGIN 
   DBMS_OUTPUT.put_line ('No rows found:'); 

   BEGIN 
      SELECT n 
        INTO my_n 
        FROM not_much_stuff 
       WHERE n = -1; 
   EXCEPTION 
      WHEN NO_DATA_FOUND 
      THEN 
         DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack); 
   END; 

   DBMS_OUTPUT.put_line ('Too many rows found:'); 

   BEGIN 
      SELECT n 
        INTO my_n 
        FROM not_much_stuff 
       WHERE n BETWEEN 1 AND 10; 
   EXCEPTION 
      WHEN TOO_MANY_ROWS 
      THEN 
         DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack); 
   END; 
END;
/

DECLARE 
   my_n   not_much_stuff.n%TYPE; 
BEGIN    
   tmr.start_timer; 
   FOR indx IN 1 .. 10000 
   LOOP 
      BEGIN 
         SELECT n 
           INTO my_n 
           FROM not_much_stuff 
          WHERE n = -1; 

         my_n := 100; 
      EXCEPTION 
         WHEN NO_DATA_FOUND 
         THEN 
            my_n := 100; 
      END; 
   END LOOP; 

   DBMS_OUTPUT.put_line (my_n); 

   tmr.show_elapsed ('Implicit Failure'); 
END;

/

DECLARE 
   my_n   not_much_stuff.n%TYPE; 
BEGIN 
   tmr.start_timer; 

   FOR indx IN 1 .. 10000 
   LOOP 
      BEGIN 
         SELECT n 
           INTO my_n 
           FROM not_much_stuff 
          WHERE n = 1; 

         my_n := 100; 
      EXCEPTION 
         WHEN NO_DATA_FOUND 
         THEN 
            my_n := 100; 
      END; 
   END LOOP; 

   DBMS_OUTPUT.put_line (my_n); 

   tmr.show_elapsed ('Implicit Success'); 
END;
/

DECLARE 
   my_n   not_much_stuff.n%TYPE; 

   CURSOR stuff_cur 
   IS 
      SELECT n 
        FROM not_much_stuff 
       WHERE n = -1; 
BEGIN 
   tmr.start_timer; 

   FOR indx IN 1 .. 10000 
   LOOP 
      OPEN stuff_cur; 

      FETCH stuff_cur INTO my_n; 

      IF stuff_cur%NOTFOUND 
      THEN 
         my_n := 100; 
      END IF; 

      CLOSE stuff_cur; 
   END LOOP; 

   DBMS_OUTPUT.put_line (my_n); 

   tmr.show_elapsed ('Explicit Failure'); 
END;
/

DECLARE 
   my_n   not_much_stuff.n%TYPE; 

   CURSOR stuff_cur 
   IS 
      SELECT n 
        FROM not_much_stuff 
       WHERE n = 1; 
BEGIN 
   tmr.start_timer; 

   FOR indx IN 1 .. 10000 
   LOOP 
      OPEN stuff_cur; 

      FETCH stuff_cur INTO my_n; 

      IF stuff_cur%FOUND 
      THEN 
         my_n := 100; 
      END IF; 

      CLOSE stuff_cur; 
   END LOOP; 

   DBMS_OUTPUT.put_line (my_n); 

   tmr.show_elapsed ('Explicit Success'); 
END;
/

-- 1. Implicit cursor inside a nested block
CREATE OR REPLACE PROCEDURE do_stuff_with_employee (  
   employee_id_in   IN hr.employees.employee_id%TYPE)  
IS  
   l_name   hr.employees.last_name%TYPE;  
BEGIN  
   BEGIN  
      SELECT last_name  
        INTO l_name  
        FROM hr.employees e  
       WHERE e.employee_id = do_stuff_with_employee.employee_id_in;  
   EXCEPTION  
      WHEN NO_DATA_FOUND  
      THEN  
         /* log the error if this really is an error or let it go... */  
         l_name := NULL;  
   END;  

   IF l_name IS NOT NULL  
   THEN  
      /* continue with application logic */  
      NULL;  
   END IF;  
END; 
/

-- 2. Implicit cursor inside a nested subprogram
CREATE OR REPLACE PROCEDURE do_stuff_with_employee (  
   employee_id_in   IN hr.employees.employee_id%TYPE)  
IS  
   l_name   hr.employees.last_name%TYPE;  

   FUNCTION emp_name (employee_id_in IN hr.employees.employee_id%TYPE)  
      RETURN hr.employees.last_name%TYPE  
   IS  
      l_name   hr.employees.last_name%TYPE;  
   BEGIN  
      SELECT last_name  
        INTO l_name  
        FROM hr.employees  
       WHERE employee_id = employee_id_in;  

      RETURN l_name;  
   EXCEPTION  
      WHEN NO_DATA_FOUND  
      THEN  
         /* log the error if this really is an error or let it go... */  
         RETURN NULL;  
   END;  
BEGIN  
   l_name := emp_name (employee_id_in);  

   IF l_name IS NOT NULL  
   THEN  
      /* continue with application logic */  
      NULL;  
   END IF;  
END; 
/

-- 3. Explicit cursor unconcerned with too many rows
CREATE OR REPLACE PROCEDURE do_stuff_with_employee (  
   employee_id_in   IN hr.employees.employee_id%TYPE)  
IS  
   l_name   hr.employees.last_name%TYPE;  

   CURSOR name_cur  
   IS  
      SELECT last_name  
        FROM hr.employees e  
       WHERE e.employee_id = do_stuff_with_employee.employee_id_in;  
BEGIN  
   OPEN name_cur;  

   FETCH name_cur INTO l_name;  

   CLOSE name_cur;  

   IF l_name IS NOT NULL  
   THEN  
      /* continue with application logic */  
      NULL;  
   END IF;  
END; 
/

-- 4. Explicit cursor that checks for too many rows
CREATE OR REPLACE PROCEDURE do_stuff_with_employee (  
   employee_id_in   IN hr.employees.employee_id%TYPE)  
IS  
   l_name    hr.employees.last_name%TYPE;  
   l_name2   hr.employees.last_name%TYPE;  

   CURSOR name_cur  
   IS  
      SELECT last_name  
        FROM hr.employees e  
       WHERE e.employee_id = do_stuff_with_employee.employee_id_in;  
BEGIN  
   OPEN name_cur;  

   FETCH name_cur INTO l_name;  

   FETCH name_cur INTO l_name2;  

   IF name_cur%FOUND  
   THEN  
      CLOSE name_cur;  

      RAISE TOO_MANY_ROWS;  
   ELSE  
      CLOSE name_cur;  
   END IF;  

   IF l_name IS NOT NULL  
   THEN  
      /* continue with application logic */  
      NULL;  
   END IF;  
END; 
/

0
投票

你可以做这些事情:

  1. 查询它。添加索引以帮助查询更快

如果最终插入:

  1. 添加唯一索引 - 并插入值 - 错误意味着它已经存在
  2. 融入其中。

0
投票

我必须说出经常用于检查记录是否已存在于数据库中的内容,但强烈建议不要使用!这是计算所有行只是为了检查:

    DECLARE
       count_var   NUMBER;
    BEGIN
       SELECT COUNT (*)
         INTO count_var
         FROM not_much_stuff
        WHERE n = -1;

       IF count_var = 0
       THEN
          DBMS_OUTPUT.put_line ('No rows found!');
       ELSIF count_var > 1
       THEN
          DBMS_OUTPUT.put_line ('Too many rows found!');
       ELSE
          DBMS_OUTPUT.put_line ('One row exists!');
       END IF;
    END;

请永远不要使用这个!这是编程懒惰的例子!

© www.soinside.com 2019 - 2024. All rights reserved.