我有下表:
我想创建一个接收类别的程序并让我回来 类别父母,像这样:
我已经成功创建了一个程序但它没有显示数据 以我想要的方式。 此外,我相信有更好的方法(可能是递归?)来完成任务,但我不知道如何实现它。你有任何提示吗?
- 数据库查询 -
-- Creating Domain Boolean (didn't exist in FireBird) --
CREATE DOMAIN DBOOLEAN
AS Smallint
DEFAULT 0
NOT NULL
check (Value in (0,1));
-- Creating table --
CREATE TABLE TCATEGORIE
(CODE_CAT Char(5) NOT NULL,
NOM_CAT DNOM,
CUISINE_CAT DBOOLEAN DEFAULT 0,
FKCATPRINC_CAT Char(5),
PRIMARY KEY (CODE_CAT)
);
-- Inserted data --
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('B', 'Boissons', 0,null);
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('BS', 'Boissons froides', 0, 'B');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('BV', 'Vins', 0, 'B');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('BVR', 'Vin rouge', 0, 'BV');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('BVB', 'Vin Blanc', 0, 'BV');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('BVROS', 'Vin Rose', 0, 'BV');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('BC', 'Boissons chaudes', 0, 'B');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('V', 'Viande', 1, null);
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('VR', 'Viande Rouge', 1, 'V');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('VB', 'Viande Blanche', 1, 'V');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('P', 'Poisson', 1, null);
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('F', 'Fromage', 1, null);
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('S', 'Sauce', 1, null);
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('D', 'Dessert', 1, null);
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('DC', 'Dessert chaud', 1, 'D');
Insert Into TCATEGORIE
(CODE_CAT, NOM_CAT, CUISINE_CAT, FKCATPRINC_CAT)
values ('DG', 'Dessert glace', 1, 'D');
- 我的程序 -
set term^;
create procedure CatParent (choix
type of column TCATEGORIE.CODE_CAT)
returns (CODE_CAT1 type of column TCATEGORIE.CODE_CAT,
CODE_CAT2 type of column TCATEGORIE.CODE_CAT,
CODE_CAT3 type of column TCATEGORIE.CODE_CAT,
NOM_CAT1 type of column TCATEGORIE.NOM_CAT,
NOM_CAT2 type of column TCATEGORIE.NOM_CAT,
NOM_CAT3 type of column TCATEGORIE.NOM_CAT )
as
begin
if(char_length(trim(choix))>=3)
then
select c.CODE_CAT, c2.CODE_CAT, c3.CODE_CAT,
c.NOM_CAT, c2.NOM_CAT, c3.NOM_CAT
from TCATEGORIE c
left join TCATEGORIE c2
on c.CODE_CAT=c2.FKCATPRINC_CAT
left join TCATEGORIE c3
on c2.CODE_CAT=c3.FKCATPRINC_CAT
where c.FKCATPRINC_CAT is null and
c3.code_cat=:choix into :CODE_CAT1, :CODE_CAT2, :CODE_CAT3,
:NOM_CAT1, :NOM_CAT2, :NOM_CAT3;
else if(char_length(trim(choix))=2)
then
select first 1 c.CODE_CAT, c2.CODE_CAT, c.NOM_CAT, c2.NOM_CAT
from TCATEGORIE c
left join TCATEGORIE c2
on c.CODE_CAT=c2.FKCATPRINC_CAT
left join TCATEGORIE c3
on c2.CODE_CAT=c3.FKCATPRINC_CAT
where c.FKCATPRINC_CAT is null and
c2.code_cat=:choix
into :CODE_CAT1, :CODE_CAT2,
:NOM_CAT1, :NOM_CAT2;
else
select first 1 c.CODE_CAT, c.NOM_CAT
from TCATEGORIE c
left join TCATEGORIE c2
on c.CODE_CAT=c2.FKCATPRINC_CAT
left join TCATEGORIE c3
on c2.CODE_CAT=c3.FKCATPRINC_CAT
where c.FKCATPRINC_CAT is null and
c.code_cat=:choix into :CODE_CAT1, :NOM_CAT1;
end^
set term;^
答案 0 :(得分:2)
SET TERM ^ ;
create or alter procedure CAT_PARENT (
ICODE_CAT varchar(5))
returns (
CODE_CAT char(20),
NOM_CAT varchar(256),
CUISINE_CAT smallint,
FKCATPRINC_CAT char(20))
as
BEGIN
FOR
select
tcategorie.code_cat,
tcategorie.nom_cat,
tcategorie.cuisine_cat,
tcategorie.fkcatprinc_cat
from tcategorie
where
(
(tcategorie.code_cat = :icode_cat)
)
INTO :CODE_CAT,
:NOM_CAT,
:CUISINE_CAT,
:FKCATPRINC_CAT
DO
BEGIN
suspend;
while (:FKCATPRINC_CAT is not null) do
begin
execute procedure cat_parent(:FKCATPRINC_CAT)
returning_values( :CODE_CAT,
:NOM_CAT,
:CUISINE_CAT,
:FKCATPRINC_CAT);
SUSPEND;
end
END
END^
SET TERM ; ^
编辑:
你也可以像这样使用CTE(Common Table Expression:
SET TERM ^ ;
create or alter procedure CAT_PARENT_CTE (
ICODE_CAT varchar(5))
returns (
CODE_CAT char(20),
NOM_CAT varchar(256))
as
BEGIN
for with recursive dept_code
as (
select tcategorie.code_cat, tcategorie.nom_cat, tcategorie.fkcatprinc_cat
from tcategorie
where (tcategorie.code_cat = :icode_cat)
union all
select tcategorie.code_cat, tcategorie.nom_cat, tcategorie.fkcatprinc_cat from dept_code
inner join tcategorie on tcategorie.code_cat = dept_code.fkcatprinc_cat
)
select dept_code.code_cat, dept_code.nom_cat from dept_code
into :CODE_CAT,:NOM_CAT
DO
BEGIN
suspend;
END
END^
答案 1 :(得分:0)
AS。适当的选择是避免使用存储过程和使用递归查询。 递归深度被硬编码为1024.但对于你的树应该足够了。
如果您的树可以长得更深,那么您将不得不回到SP。
如果你想使用SP,那么你必须写一个SELECTABLE
程序。
而不是Execute Procedure
(根据定义是一行动作)
你必须尝试使用下面的程序Select * from CatParent('BVROS')
。
create procedure CatParent (choix
type of column TCATEGORIE.CODE_CAT)
returns (CODE type of column TCATEGORIE.CODE_CAT,
NOM type of column TCATEGORIE.NOM_CAT
)
as
DECLARE VARIABLE ParentCode type of column TCATEGORIE.CODE_CAT;
begin
CODE = :choix;
While ( 0 = 0 ) DO BEGIN
if ( CODE is not null ) then LEAVE; -- already traversed to root
NOM = NULL;
SELECT NOM_CAT, FKCATPRINC_CAT FROM TCATEGORIE
WHERE :CODE = CODE_CAT
INTO :NOM, :ParentCode;
if ( :NOM is NULL ) then LEAVE;
-- This code does not exists, tree is broken, Error.
-- Or empty name, Error too.
SUSPEND; -- yield results into the "table"
CODE = :ParentCode; -- prepare for searching next parent
END;
end;