检查新行的日期是否与表中的现有日期重叠的过程

时间:2012-12-20 20:19:43

标签: sql oracle plsql oracle11g

我正在尝试编写一个过程来检查给定的参数(日期)是否位于表中任何现有日期之间。如果没有插入新行。

CREATE OR REPLACE PROCEDURE test(date1 IN DATE, date2 IN DATE) AS 
  ddate1 DATE;
  ddate2 DATE;
  quer VARCHAR2(50);
BEGIN 
  SELECT fdate, tdate INTO ddate1, ddate2 FROM dataHolder; 
  IF (ddate1 < date1) AND (ddate2 > date2) THEN
    quer := 'invalid'; 
  ELSE 
    INSERT INTO dataHolder VALUES (date1, date2);
    quer := 'success';
  END IF; 
  DBMS_OUTPUT.PUT_LINE(quer); 
END;
/

我尝试过这样的事情但是在执行时我得到了这个错误:

ORA-01422: exact fetch returns more than requested number of rows

3 个答案:

答案 0 :(得分:1)

您收到该错误是因为您的select语句返回了多条记录。要简化该过程,您可以使用merge语句并按如下方式重写您的过程:

CREATE OR REPLACE PROCEDURE test(date1 IN DATE, date2 IN DATE) AS
BEGIN
  merge into Dataholder dh
  using dual
     on ((date1 < dh.fdate) and (date2 < dh.tdate))
  when not matched then
    insert (dh.fdate, dh.tdate)
      values(date1, date2);
  if sql%rowcount > 0
  then
    dbms_output.put_line('success');
  else
    dbms_output.put_line('invalid');
  end if;
END; 

答案 1 :(得分:1)

您的select语句提取的内容多于记录,而您的代码只需要一个,因为您正在获取单值变量。您可以使用BULK COLLECT并将所有日期收集到日期集合中,但我认为您可以使用以下代码改进它:

CREATE OR REPLACE PROCEDURE test(date1 IN DATE, date2 IN DATE) AS 
  ddate1 DATE;
  ddate2 DATE;
  invalidRecords NUMBER := 0;
  quer VARCHAR2(50);
BEGIN
   SELECT COUNT(1) INTO invalidRecords FROM dataHolder WHERE fdate < date1 AND tdate > date2; 

   IF (invalidRecords > 0) THEN
     quer := 'invalid'; 
   ELSE
     INSERT INTO dataHolder VALUES (date1, date2);
     quer := 'success';
   END IF;

   DBMS_OUTPUT.PUT_LINE(quer); 
END;
/

由于COUNT(1)将始终只返回一条记录,因此它永远不会抛出ORA-01422错误。此外,它将始终返回数据,因此您无需担心NO_DATA_FOUND,因为如果没有无效记录,将获取值0。

答案 2 :(得分:0)

Nuno Guerreiro的一些小优化答案

SELECT COUNT(1) INTO invalidRecords 
FROM dual 
WHERE exists 
  (SELECT 1 FROM dataHolder WHERE fdate < date1 AND tdate > date2);

它将允许不计数。