2016-08-07 2 views
2

(어떻게 SQL을 사용하여 상위 범주를 찾을 수) 나는 다음과 같은 테이블이 :파이어 버드

enter image description here

나는이 같은 카테고리 부모 범주에 소요 날 다시 제공하는 절차를 만들려면 :

enter image description here

은 이미 프로 시저를 만들 succeded했지만 그것은 내가 원하는 방식으로 데이터를 를 표시하지 않습니다. 게다가, 나는 더 나은 방법 (아마 재귀?) 작업을 달성하기 위해,하지만 그것을 구현하는 방법을 모르겠다 믿습니다. 어떤 힌트가 있습니까?

--database Query--

-- 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'); 

아니야 자,가요 Procedure--

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;^ 

답변

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^ 
+0

청소 및 간결. 놀라운, 고마워요 :) – SebastianJ

+0

@SebastianJ 오신 것을 환영합니다. 나는 anoter 기술도 추가했다. 편집을 참조하십시오. –

0

AS. 적절한 옵션은 저장 프로 시저를 사용하지 않고 재귀 쿼리를 사용하지 않는 것입니다. 재귀 깊이는 1024로 하드 코드되어 있습니다.하지만 트리가 충분해야합니다.

  • http://firebirdsql.su/doku.php?id=recursive
  • 당신의 나무가 깊은 성장할 수있는 경우 How can I create "recursive sql"

    • , 당신은 다시 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;