我正在为假想的视频租赁商店创建数据库。 我需要做的就是检查特定电影的可用性的程序(显然电影可以有多个副本)。因此,我必须检查是否有可用于租金的副本,并获取副本的编号(因为它将在以后影响其他触发...)。 我已经用游标做了所有事情并且它实际上工作得非常好,但我需要(即#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(价格)
每部电影都可以有多个副本。 每种副本都可以在两种情况下使用:
我尝试过的查询是以下内容,根本不起作用:
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(即使只是行列表中的第一个)。
答案 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!你的建议几乎解决了这个问题。