定义一种方法,通过从其他表中引用的字段对记录进行分组

Define a method to group records by a field referenced from other tables

我设计了一个Oracle数据库如下。我的问题是,如何在BodyModel_TYPE中定义一个函数来显示没有。每个车身模型中的单层巴士,而该功能必须接受特定的车身模型,如 input/parameter.

Diagram for the following database schema

我编码的方法是这样的:

ALTER TYPE BodyModel_TYPE
   ADD MEMBER FUNCTION cal_single_deck_bus RETURN int
   CASCADE;

CREATE OR REPLACE TYPE BODY BodyModel_TYPE AS
MEMBER FUNCTION cal_single_deck_bus RETURN int IS
N int;
BEGIN
SELECT COUNT(t.BUSID) INTO N FROM SINGLEDECKBUS_TABLE T WHERE DEREF(t.BODYMODEL) = self;
RETURN N;
END cal_single_deck_bus;
END;
/

它没有输入,但返回的结果不是预期的。完整的sql代码如下:

-- Engine Model

create or replace type EngineModel_TYPE as object
(EngineModelID int,
EngineDescription varchar2(45),
EngineType varchar2(25),
EngineCapacity int);
/

create table EngineModel_TABLE of EngineModel_TYPE;

alter table EngineModel_TABLE
add constraint EngineModelID_PK primary key (EngineModelID);

-- Body Model

create or replace type BodyModel_TYPE as object
(ModelID int,
ModelName varchar2(45),
FloorType varchar2(5),
Manufacturer varchar2(45),
Length number(8,2),
Width number(8,2),
NoOfAxles int);
/

create table BodyModel_TABLE of BodyModel_TYPE;

alter table BodyModel_TABLE
add constraint BodyModelID_PK primary key (ModelID);

-- Bus 

create or replace type Bus_TYPE as object
(BusID int,
RegistrationNo VARCHAR2(10),
RegistrationExpireDate date,
EngineModel REF EngineModel_TYPE,
BodyModel REF BodyModel_TYPE) NOT FINAL;
/

-- Single Decker Bus

CREATE OR REPLACE TYPE SingleDeckBus_type UNDER Bus_type
(NoOfDoors INT,
SeatingCapacity int,
StandingCapacity int);
/
CREATE TABLE SingleDeckBus_table OF SingleDeckBus_type;

ALTER TABLE SingleDeckBus_table
ADD CONSTRAINT SingleDeckBus_BusId_pk PRIMARY KEY (BusId);

-- Double Decker bus

CREATE OR REPLACE TYPE DoubleDeckBus_type UNDER Bus_type
(LowerDeckSeatingCapacity int,
LowerDeckStandingCapacity int,
LuggageCapacity number(8,2),
UpperDeckSeatingCapacity int);
/
CREATE TABLE DoubleDeckBus_table OF DoubleDeckBus_type;

ALTER TABLE DoubleDeckBus_table
ADD CONSTRAINT DoubleDeckBus_BusId_pk PRIMARY KEY (BusId);

-- Accessory

CREATE OR REPLACE TYPE Accessory_type AS OBJECT
(AccessoryId INT,
AccessoryName VARCHAR2(45),
AccessoryDescription VARCHAR2(45),
InstallDate DATE,
SingleDeckBus REF SingleDeckBus_type,
DoubleDeckBus REF DoubleDeckBus_type);
/
CREATE TABLE Accessory_table OF Accessory_type;

ALTER TABLE Accessory_table
ADD CONSTRAINT AccessoryId_pk PRIMARY KEY(AccessoryId);


-- 2.   Insert record statements (3 records for each table that support testing of your queries) 

insert into EngineModel_TABLE values
(1, 'Description 1', 'Type 1', 10); 
insert into EngineModel_TABLE values
(2, 'Description 2', 'Type 2', 20);
insert into EngineModel_TABLE values
(3, 'Description 3', 'Type 3', 30);

insert into BodyModel_TABLE values
(1, 'name 1', 'Type1', 'manufac1', 10.1, 5.1, 10); 
insert into BodyModel_TABLE values
(2, 'name 2', 'Type2', 'manufac2', 10.2, 5.2, 20); 
insert into BodyModel_TABLE values
(3, 'name 3', 'Type3', 'manufac3', 10.3, 5.3, 30); 

insert into SingleDeckBus_table
SELECT 1, 'SA01', '1-Jan-2020', REF(E), REF(B), 1, 20, 10 from ENGINEMODEL_TABLE E, BODYMODEL_TABLE B 
where E.ENGINEMODELID = 1 AND B.MODELID = 1;
insert into SingleDeckBus_table
SELECT 2, 'SA02', '2-Jan-2020', REF(E), REF(B), 2, 25, 10 from ENGINEMODEL_TABLE E, BODYMODEL_TABLE B 
where E.ENGINEMODELID = 2 AND B.MODELID = 2;
insert into SingleDeckBus_table
SELECT 3, 'SA03', '3-Jan-2020', REF(E), REF(B), 3, 30, 10 from ENGINEMODEL_TABLE E, BODYMODEL_TABLE B 
where E.ENGINEMODELID = 3 AND B.MODELID = 3;
insert into SingleDeckBus_table
SELECT 55, 'SA03', '3-Jan-2020', REF(E), REF(B), 3, 30, 10 from ENGINEMODEL_TABLE E, BODYMODEL_TABLE B 
where E.ENGINEMODELID = 3 AND B.MODELID = 3;

insert into DOUBLEDECKBUS_TABLE
SELECT 4, 'SA04', '4-Jan-2020', REF(E), REF(B), 20, 10, 30.15, 20 from ENGINEMODEL_TABLE E, BODYMODEL_TABLE B 
where E.ENGINEMODELID = 1 AND B.MODELID = 1;
insert into DOUBLEDECKBUS_TABLE
SELECT 5, 'SA05', '5-Jan-2020', REF(E), REF(B), 25, 10, 35.15, 25 from ENGINEMODEL_TABLE E, BODYMODEL_TABLE B 
where E.ENGINEMODELID = 2 AND B.MODELID = 2;
insert into DOUBLEDECKBUS_TABLE
SELECT 6, 'SA06', '6-Jan-2020', REF(E), REF(B), 30, 10, 40.15, 30 from ENGINEMODEL_TABLE E, BODYMODEL_TABLE B 
where E.ENGINEMODELID = 3 AND B.MODELID = 3;

insert into ACCESSORY_TABLE
SELECT 1, 'Acc1', 'AccDesc1', '1-Mar-2017', REF(S), REF(D) from SINGLEDECKBUS_TABLE S, DOUBLEDECKBUS_TABLE D 
where s.BUSID = 1 AND d.BUSID = 4;
insert into ACCESSORY_TABLE
SELECT 2, 'Acc2', 'AccDesc2', '2-Mar-2017', REF(S), REF(D) from SINGLEDECKBUS_TABLE S, DOUBLEDECKBUS_TABLE D 
where s.BUSID = 2 AND d.BUSID = 5;
insert into ACCESSORY_TABLE
SELECT 3, 'Acc3', 'AccDesc3', '3-Mar-2017', REF(S), REF(D) from SINGLEDECKBUS_TABLE S, DOUBLEDECKBUS_TABLE D 
where s.BUSID = 3 AND d.BUSID = 6;

-- 3.   Create a method in the appropriate class to display how many single deck buses in each body model.

   ALTER TYPE BodyModel_TYPE
   ADD MEMBER FUNCTION cal_single_deck_bus RETURN int
   CASCADE;

CREATE OR REPLACE TYPE BODY BodyModel_TYPE AS
MEMBER FUNCTION cal_single_deck_bus RETURN int IS
N int;
BEGIN
SELECT COUNT(t.BUSID) INTO N FROM SINGLEDECKBUS_TABLE T WHERE DEREF(t.BODYMODEL) = self;
RETURN N;
END cal_single_deck_bus;
END;
/

commit;

根据您显示的插入内容,您现有的方法函数似乎得到了正确的结果:

SELECT b.ModelID, b.ModelName, b.cal_single_deck_bus() AS single_deck_bus_count
FROM BodyModel_TABLE b;

   MODELID MODELNAME            SINGLE_DECK_BUS_COUNT
---------- -------------------- ---------------------
         1 name 1                                   1
         2 name 2                                   1
         3 name 3                                   2

这似乎是一种合理的方法。但是,如果您的作业指定该函数必须接受 body 模型——我不认为你的问题 3 的措辞是这样,除非你遗漏了其中的一部分——那么你可能想要 a static function, 不是成员函数:

-- remove your existing member function first
ALTER TYPE BodyModel_TYPE
DROP MEMBER FUNCTION cal_single_deck_bus RETURN int
CASCADE;

ALTER TYPE BodyModel_TYPE
ADD STATIC FUNCTION cal_single_deck_bus (p_bodymodel REF BodyModel_TYPE)
RETURN int CASCADE;

CREATE OR REPLACE TYPE BODY BodyModel_TYPE AS
STATIC FUNCTION cal_single_deck_bus (p_bodymodel REF BodyModel_TYPE)
RETURN int IS
  N int;
BEGIN
  SELECT COUNT(t.BUSID) INTO N
  FROM SINGLEDECKBUS_TABLE T
  WHERE t.BODYMODEL = p_bodymodel;

  RETURN N;
END cal_single_deck_bus;
END;
/

然后您可以将任何相关表的特定引用传递给静态函数,或者获取所有 body 类型的计数,例如:

SELECT b.ModelID, b.ModelName,
  BodyModel_TYPE.cal_single_deck_bus(ref(b)) AS single_deck_bus_count
FROM BodyModel_TABLE b;

   MODELID MODELNAME            SINGLE_DECK_BUS_COUNT
---------- -------------------- ---------------------
         1 name 1                                   1
         2 name 2                                   1
         3 name 3                                   2

BodyModel_TYPE.cal_single_deck_bus(ref(b)) 是一个静态调用,因为它针对的是类型本身而不是该类型的实例;与之前的 b.cal_single_deck_bus() 调用进行比较。在这两种情况下,b 都是 object 类型的实例。

您也可以从其他地方获取参考,例如以一种相当做作的方式:

SELECT d.BusID, d.UpperDeckSeatingCapacity,
  deref(d.BodyModel).ModelID as ModelID,
  deref(d.BodyModel).ModelName as ModelName,
  BodyModel_TYPE.cal_single_deck_bus(d.BodyModel) AS single_deck_bus_count
FROM DoubleDeckBus_TABLE d
WHERE d.RegistrationNo = 'SA06';

     BUSID UPPERDECKSEATINGCAPACITY    MODELID MODELNAME            SINGLE_DECK_BUS_COUNT
---------- ------------------------ ---------- -------------------- ---------------------
         6                       30          3 name 3                                   2

如果您想传入模型 ID 而不是 object 引用,则需要在静态函数中将 body 模型和 single-decker 总线表连接在一起:

-- remove your existing member function first
ALTER TYPE BodyModel_TYPE
DROP STATIC FUNCTION cal_single_deck_bus (p_bodymodel REF BodyModel_TYPE) RETURN int
CASCADE;

ALTER TYPE BodyModel_TYPE
ADD STATIC FUNCTION cal_single_deck_bus (p_modelid int)
RETURN int CASCADE;

CREATE OR REPLACE TYPE BODY BodyModel_TYPE AS
STATIC FUNCTION cal_single_deck_bus (p_modelid int)
RETURN int IS
  N int;
BEGIN
  SELECT COUNT(sd.BUSID) INTO N
  FROM BODYMODEL_TABLE b
  JOIN SINGLEDECKBUS_TABLE sd
  ON sd.BODYMODEL = REF(b)
  WHERE b.ModelID = p_modelid;

  RETURN N;
END cal_single_deck_bus;
END;
/

那么你可以这样称呼它:

SELECT BodyModel_TYPE.cal_single_deck_bus(3) AS single_deck_bus_count FROM dual;

SINGLE_DECK_BUS_COUNT
---------------------
                    2

或者如果您还想显示相关信息:

SELECT b.ModelID, b.ModelName,
  BodyModel_TYPE.cal_single_deck_bus(b.ModelID) AS single_deck_bus_count
FROM BodyModel_TABLE b;

   MODELID MODELNAME            SINGLE_DECK_BUS_COUNT
---------- -------------------- ---------------------
         1 name 1                                   1
         2 name 2                                   1
         3 name 3                                   2