【问题标题】:Hierarchical Oracle inserts. Ensure that every parent has at most one child分层 Oracle 插入。确保每个父母最多有一个孩子
【发布时间】: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


【解决方案1】:

您只需要在您的表上创建一个Unique Index 以确保不会重复任何员工,避免员工拥有多个经理。

create unique index uk_unique_employee on "HR"."MY_EMPLOYEES" (EMPLOYEE_ID); 

编辑

关于您的最后一条评论:“Jorge,该表的问题在于,可以创建一个员工与一个不存在的经理。”

所以你只需要在EMPLOYEE_IDMANAGER_ID 列中添加一个外键约束,例如:

alter table "HR"."MY_EMPLOYEES" 
    add constraint fk_employee_manager
        foreign key (MANAGER_ID)
        references "HR"."MY_EMPLOYEES" (EMPLOYEE_ID);

请注意,为了创建 FOREIGN KEY,列必须是主键或在其上具有索引(前面的命令确保了这一点)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多