分层 Oracle 插入。确保每个 parent 最多有一个 child
Hierarchical Oracle inserts. Ensure that every parent has at most one child
我的示例数据库有一个存储员工的 table,其中 employee_id 是主键,manager_id 是 employee_id
下图是某公司的层级结构。
employee_id没有经理(是老板!),1021管理1022。
当我执行
SELECT last_name, employee_id, manager_id, LEVEL
FROM my_employees
START WITH employee_id = 1020
CONNECT BY PRIOR employee_id = manager_id;
我要收回公司层级:
LAST_NAME EMPLOYEE_ID MANAGER_ID LEVEL
------------------------- ----------- ---------- ----------
Test 1020 1
Test2 1021 1020 2
Test3 1022 1021 3
我想增强此功能以验证每个 parent(即 EMPLOYEE_ID)将只有唯一的 (ONE) child。
例如,这在我的 table:
中是可能的
LAST_NAME EMPLOYEE_ID MANAGER_ID LEVEL
------------------------- ----------- ---------- ----------
Test 1020 1
Test2 1021 1020 2
Test3 1022 1021 3
Test4 1023 1021 3
Test4和Test3有同一个manager(test3和test4是同一级别的)。
我的要求是在数据库架构中找到一种简单的方法,以确保 "an employee can not have two managers no matter the level" 并且一名经理不能拥有超过 1 名属于下一级的员工。
创建我的 table/trigger 和序列的 sql 脚本如下:
--------------------------------------------------------
-- DDL for Sequence MY_EMPLOYEES_SEQ
--------------------------------------------------------
CREATE SEQUENCE "HR"."MY_EMPLOYEES_SEQ" MINVALUE 1 MAXVALUE 999999999999999 INCREMENT BY 1 START WITH 1020 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE GLOBAL ;
--------------------------------------------------------
-- DDL for Table MY_EMPLOYEES
--------------------------------------------------------
CREATE TABLE "HR"."MY_EMPLOYEES"
( "EMPLOYEE_ID" NUMBER(6,0),
"FIRST_NAME" VARCHAR2(20 BYTE),
"LAST_NAME" VARCHAR2(25 BYTE),
"EMAIL" VARCHAR2(25 BYTE),
"PHONE_NUMBER" VARCHAR2(20 BYTE),
"HIRE_DATE" DATE,
"SALARY" NUMBER(8,0),
"MANAGER_ID" NUMBER(6,0)
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ;
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."EMPLOYEE_ID" IS 'The primary key';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."FIRST_NAME" IS 'First Name';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."LAST_NAME" IS 'Last Name';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."EMAIL" IS 'Email Id';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."PHONE_NUMBER" IS 'Phone Number
';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."HIRE_DATE" IS 'Hire Date';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."SALARY" IS 'Enfornced by check';
--------------------------------------------------------
-- DDL for Index MY_EMPLOYEES_UK1
--------------------------------------------------------
CREATE UNIQUE INDEX "HR"."MY_EMPLOYEES_UK1" ON "HR"."MY_EMPLOYEES" ("EMAIL")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ;
--------------------------------------------------------
-- DDL for Index MY_EMPLOEES_PK
--------------------------------------------------------
CREATE UNIQUE INDEX "HR"."MY_EMPLOEES_PK" ON "HR"."MY_EMPLOYEES" ("EMPLOYEE_ID")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ;
--------------------------------------------------------
-- DDL for Trigger MY_EMPL_TRIG_1
--------------------------------------------------------
CREATE OR REPLACE EDITIONABLE TRIGGER "HR"."MY_EMPL_TRIG_1"
before insert on "HR"."MY_EMPLOYEES"
for each row
begin
if inserting then
if :NEW."EMPLOYEE_ID" is null then
select MY_EMPLOYEES_SEQ.nextval into :NEW."EMPLOYEE_ID" from dual;
end if;
end if;
end;
/
ALTER TRIGGER "HR"."MY_EMPL_TRIG_1" ENABLE;
--------------------------------------------------------
-- Constraints for Table MY_EMPLOYEES
--------------------------------------------------------
ALTER TABLE "HR"."MY_EMPLOYEES" MODIFY ("EMPLOYEE_ID" NOT NULL ENABLE);
ALTER TABLE "HR"."MY_EMPLOYEES" MODIFY ("LAST_NAME" NOT NULL ENABLE);
ALTER TABLE "HR"."MY_EMPLOYEES" MODIFY ("EMAIL" NOT NULL ENABLE);
ALTER TABLE "HR"."MY_EMPLOYEES" MODIFY ("HIRE_DATE" NOT NULL ENABLE);
ALTER TABLE "HR"."MY_EMPLOYEES" ADD CONSTRAINT "MY_EMPLOEES_PK" PRIMARY KEY ("EMPLOYEE_ID")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ENABLE;
ALTER TABLE "HR"."MY_EMPLOYEES" ADD CONSTRAINT "MY_EMPLOYEES_UK1" UNIQUE ("EMAIL")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ENABLE;
ALTER TABLE "HR"."MY_EMPLOYEES" ADD CONSTRAINT "MY_EMPLOYEES_CHK1" CHECK (salary > 0) ENABLE;
您只需要在 table 上创建一个 Unique Index 以确保不会重复任何员工,避免一名员工拥有多个经理。
create unique index uk_unique_employee on "HR"."MY_EMPLOYEES" (EMPLOYEE_ID);
编辑
关于您的最后一条评论:"Jorge, what is wrong wit the table is that it possible to create a employee with a manager that does not EXIST."
所以你只需要在 MANAGER_ID
列中的 EMPLOYEE_ID
添加外键约束,例如:
alter table "HR"."MY_EMPLOYEES"
add constraint fk_employee_manager
foreign key (MANAGER_ID)
references "HR"."MY_EMPLOYEES" (EMPLOYEE_ID);
请注意,为了创建 FOREIGN KEY,该列必须是主键或在其上有索引(前面的命令确保了这一点)。
我的示例数据库有一个存储员工的 table,其中 employee_id 是主键,manager_id 是 employee_id
下图是某公司的层级结构。 employee_id没有经理(是老板!),1021管理1022。
当我执行
SELECT last_name, employee_id, manager_id, LEVEL
FROM my_employees
START WITH employee_id = 1020
CONNECT BY PRIOR employee_id = manager_id;
我要收回公司层级:
LAST_NAME EMPLOYEE_ID MANAGER_ID LEVEL
------------------------- ----------- ---------- ----------
Test 1020 1
Test2 1021 1020 2
Test3 1022 1021 3
我想增强此功能以验证每个 parent(即 EMPLOYEE_ID)将只有唯一的 (ONE) child。
例如,这在我的 table:
中是可能的LAST_NAME EMPLOYEE_ID MANAGER_ID LEVEL
------------------------- ----------- ---------- ----------
Test 1020 1
Test2 1021 1020 2
Test3 1022 1021 3
Test4 1023 1021 3
Test4和Test3有同一个manager(test3和test4是同一级别的)。
我的要求是在数据库架构中找到一种简单的方法,以确保 "an employee can not have two managers no matter the level" 并且一名经理不能拥有超过 1 名属于下一级的员工。
创建我的 table/trigger 和序列的 sql 脚本如下:
--------------------------------------------------------
-- DDL for Sequence MY_EMPLOYEES_SEQ
--------------------------------------------------------
CREATE SEQUENCE "HR"."MY_EMPLOYEES_SEQ" MINVALUE 1 MAXVALUE 999999999999999 INCREMENT BY 1 START WITH 1020 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE GLOBAL ;
--------------------------------------------------------
-- DDL for Table MY_EMPLOYEES
--------------------------------------------------------
CREATE TABLE "HR"."MY_EMPLOYEES"
( "EMPLOYEE_ID" NUMBER(6,0),
"FIRST_NAME" VARCHAR2(20 BYTE),
"LAST_NAME" VARCHAR2(25 BYTE),
"EMAIL" VARCHAR2(25 BYTE),
"PHONE_NUMBER" VARCHAR2(20 BYTE),
"HIRE_DATE" DATE,
"SALARY" NUMBER(8,0),
"MANAGER_ID" NUMBER(6,0)
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ;
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."EMPLOYEE_ID" IS 'The primary key';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."FIRST_NAME" IS 'First Name';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."LAST_NAME" IS 'Last Name';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."EMAIL" IS 'Email Id';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."PHONE_NUMBER" IS 'Phone Number
';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."HIRE_DATE" IS 'Hire Date';
COMMENT ON COLUMN "HR"."MY_EMPLOYEES"."SALARY" IS 'Enfornced by check';
--------------------------------------------------------
-- DDL for Index MY_EMPLOYEES_UK1
--------------------------------------------------------
CREATE UNIQUE INDEX "HR"."MY_EMPLOYEES_UK1" ON "HR"."MY_EMPLOYEES" ("EMAIL")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ;
--------------------------------------------------------
-- DDL for Index MY_EMPLOEES_PK
--------------------------------------------------------
CREATE UNIQUE INDEX "HR"."MY_EMPLOEES_PK" ON "HR"."MY_EMPLOYEES" ("EMPLOYEE_ID")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ;
--------------------------------------------------------
-- DDL for Trigger MY_EMPL_TRIG_1
--------------------------------------------------------
CREATE OR REPLACE EDITIONABLE TRIGGER "HR"."MY_EMPL_TRIG_1"
before insert on "HR"."MY_EMPLOYEES"
for each row
begin
if inserting then
if :NEW."EMPLOYEE_ID" is null then
select MY_EMPLOYEES_SEQ.nextval into :NEW."EMPLOYEE_ID" from dual;
end if;
end if;
end;
/
ALTER TRIGGER "HR"."MY_EMPL_TRIG_1" ENABLE;
--------------------------------------------------------
-- Constraints for Table MY_EMPLOYEES
--------------------------------------------------------
ALTER TABLE "HR"."MY_EMPLOYEES" MODIFY ("EMPLOYEE_ID" NOT NULL ENABLE);
ALTER TABLE "HR"."MY_EMPLOYEES" MODIFY ("LAST_NAME" NOT NULL ENABLE);
ALTER TABLE "HR"."MY_EMPLOYEES" MODIFY ("EMAIL" NOT NULL ENABLE);
ALTER TABLE "HR"."MY_EMPLOYEES" MODIFY ("HIRE_DATE" NOT NULL ENABLE);
ALTER TABLE "HR"."MY_EMPLOYEES" ADD CONSTRAINT "MY_EMPLOEES_PK" PRIMARY KEY ("EMPLOYEE_ID")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ENABLE;
ALTER TABLE "HR"."MY_EMPLOYEES" ADD CONSTRAINT "MY_EMPLOYEES_UK1" UNIQUE ("EMAIL")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ENABLE;
ALTER TABLE "HR"."MY_EMPLOYEES" ADD CONSTRAINT "MY_EMPLOYEES_CHK1" CHECK (salary > 0) ENABLE;
您只需要在 table 上创建一个 Unique Index 以确保不会重复任何员工,避免一名员工拥有多个经理。
create unique index uk_unique_employee on "HR"."MY_EMPLOYEES" (EMPLOYEE_ID);
编辑
关于您的最后一条评论:"Jorge, what is wrong wit the table is that it possible to create a employee with a manager that does not EXIST."
所以你只需要在 MANAGER_ID
列中的 EMPLOYEE_ID
添加外键约束,例如:
alter table "HR"."MY_EMPLOYEES"
add constraint fk_employee_manager
foreign key (MANAGER_ID)
references "HR"."MY_EMPLOYEES" (EMPLOYEE_ID);
请注意,为了创建 FOREIGN KEY,该列必须是主键或在其上有索引(前面的命令确保了这一点)。