SQL查询而不是游标

时间:2014-04-18 10:31:30

标签: sql database oracle cursor

我正在为假想的视频租赁商店创建数据库。 我需要做的就是检查特定电影的可用性的程序(显然电影可以有多个副本)。因此,我必须检查是否有可用于租金的副本,并获取副本的编号(因为它将在以后影响其他触发...)。 我已经用游标做了所有事情并且它实际上工作得非常好,但我需要(即#34;必须")不使用游标而只是使用"纯sql" (即查询)。

我将简要解释一下我的数据库的方案:

此程序将使用的表格为3:' Copia Film' (电影拷贝),'包括' (包括),' Noleggio' (租)。

  

Copia Film Table具有以下属性:

     
      
  • idCopia
  •   
  • Genere(FK参考电影)
  •   
  • Titolo(FK参考电影)
  •   
  • dataUscita(FK参考电影)
  •   
     

包括表格:

     
      
  • idNoleggio(FK引用Noleggio。表示idRent)
  •   
  • idCopia(FK引用Copia电影。意味着idCopy)
  •   
     

Noleggio表:

     
      
  • idNoleggio(PK)
  •   
  • dataNoleggio(dateOfRent)
  •   
  • dataRestituzione(dateReturn)
  •   
  • dateRestituito(dateReturned)
  •   
  • CF(FK to Person)
  •   
  • Prezzo(价格)
  •   

每部电影都可以有多个副本。 每种副本都可以在两种情况下使用:

  1. 包含表中不存在副本ID(这意味着租用了特定副本)
  2. 副本ID出现在Include表中,而dataRestituito(dateReturned)不为空(这意味着特定副本已经租用但已经返回)
  3. 我尝试过的查询是以下内容,根本不起作用:

     SELECT COUNT(*)
     FROM NOLEGGIO
     WHERE dataNoleggio IS NOT NULL AND dataRestituito IS NOT NULL AND idNoleggio IN (
       SELECT N.idNoleggio
       FROM NOLEGGIO N JOIN INCLUDE I ON N.idNoleggio=I.idNoleggio
       WHERE idCopia IN (
         SELECT idCopia
         FROM COPIA_FILM
         WHERE titolo='Pulp Fiction')) -- Of course the title is just an example
    

    嗯,从上面的查询中我无法确定所选电影的副本是否可用如果电影的副本可用,我就无法获取副本ID。

    (如果你愿意,我可以粘贴正常工作的游标行)

    ------使用'解决方案' ---- 我修改了一下你的代码

    WITH film
    as
    (
      SELECT idCopia,titolo
        FROM COPIA_FILM
        WHERE titolo = 'Pulp Fiction'
    ),
    copy_info as
    (
      SELECT N.idNoleggio, N.dataNoleggio, N.dataRestituito, I.idCopia
        FROM NOLEGGIO N JOIN INCLUDE I ON N.idNoleggio = I.idNoleggio
    ),
    avl as
    (
      SELECT film.titolo, copy_info.idNoleggio, copy_info.dataNoleggio,
        copy_film.dataRestituito,film.idCopia
        FROM film LEFT OUTER JOIN copy_info
        ON film.idCopia = copy_info.idCopia
    )
    SELECT COUNT(*),idCopia FROM avl
    WHERE(dataRestituito IS NOT NULL OR idNoleggio IS NULL)
    GROUP BY idCopia
    

    正如我在评论中所说,如果我只是在查询中使用它,这段代码可以正常工作,但是一旦我尝试从这个程序中创建一个程序,我就会出错。 问题是最终的SELECT:

    SELECT COUNT(*), idCopia INTO CNT,COPYFILM
    FROM avl
    WHERE (dataRestituito IS NOT NULL OR idNoleggio IS NULL)
    GROUP BY idCopia
    

    错误是: ORA-01422:精确提取返回超过请求的行数 ORA-06512:at" VIDEO.PR_AVAILABILITY",第9行。

    所以看起来Into子句是错误的,因为显然查询会返回更多行。我能做什么 ?我需要在不使用游标的情况下获取复制ID(即使只是行列表中的第一个)。

3 个答案:

答案 0 :(得分:1)

你可以试试这个 -

WITH film
as
(
 SELECT idCopia, titolo
     FROM COPIA_FILM
     WHERE titolo='Pulp Fiction'
),
copy_info as
(
select N.idNoleggio, I.dataNoleggio , I.dataRestituito , I.idCopia
   FROM NOLEGGIO N JOIN INCLUDE I ON N.idNoleggio=I.idNoleggio
),
avl as
(
select film.titolo, copy_info.idNoleggio, copy_info.dataNoleggio, 
copy_info.dataRestituito   
from film LEFT OUTER JOIN copy_info
ON film.idCopia = copy_info.idCopia 
)
select * from avl
where (dataRestituito IS NOT NULL OR idNoleggio IS NULL);

答案 1 :(得分:1)

你应该考虑集合而不是记录。 如果你发现所有电影都已经出局,你可以将它们从你的股票中排除,剩下的就可以出租了。

select copiafilm.* from @f copiafilm 
left join
(
    select idCopia from @r Noleggio 
    inner join @i include on Noleggio.idNoleggio = include.idNoleggio 
    where dateRestituito is null
) out
    on copiafilm.idCopia = out.idCopia
where out.idCopia is null

答案 2 :(得分:0)

我解决了将上一个查询编辑成这个问题的问题:

SELECT COUNT(*),idCopia INTO CNT,idCopiaFilm
FROM avl
WHERE (dataRestituito IS NOT NULL OR idNoleggio IS NULL) AND rownum = 1
GROUP BY idCopia;

IF CNT > 0 THEN
  -- FOUND AVAILABLE COPY
END IF;

EXCEPTION
WHEN NO_DATA_FOUND THEN
  -- NOT FOUND AVAILABLE COPY

谢谢@Aditya Kakirde!你的建议几乎解决了这个问题。