【发布时间】:2017-12-15 20:16:55
【问题描述】:
我的示例数据库有一个存储员工的表,其中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
我想增强此功能,以验证每个父级(即 EMPLOYEE_ID)是否只有一个唯一的 (ONE) 子级。
例如,这在我的表中是可能的:
LAST_NAME EMPLOYEE_ID MANAGER_ID LEVEL
------------------------- ----------- ---------- ----------
Test 1020 1
Test2 1021 1020 2
Test3 1022 1021 3
Test4 1023 1021 3
Test4 和 Test3 具有相同的管理器(test3 和 test4 是同一级别)。
我的要求是在数据库模式中找到一种简单的方法,以确保“无论级别如何,一个员工都不能有两个经理”并且一个经理不能有超过 1 个属于下一个级别的员工。
创建我的表/触发器和序列的 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;
【问题讨论】:
-
如果我理解正确,你只需要在 manager_id 列上添加一个唯一索引,允许空值,当然,虽然这个要求很奇怪。
-
@JorgeCampos 我该怎么做你所描述的?为什么这很奇怪?
-
我没有理解你所说的每个父母都有一个独特的孩子。
-
我真的认为你在那里搞砸了。我认为你想要的是一个经理可以有很多员工,但一个员工不能有两个经理,无论级别如何。
-
独一无二的也将保证这一点。为了满足您的要求,每位员工只需一行。
标签: database oracle oracle11g oracle12c