如何链接三个表?

时间:2018-04-22 07:50:34

标签: sql firebird

我是SQL的新手并请求您的帮助 共有3个表格,分别为"Employees""Positions""EmployeesPositions"。 例如,2 positions可以附加到一个employee。 如何链接表,以便不会发生重复?我读到了外键和 JOIN ,但我还没弄清楚如何正确地做到这一点。

表格结构:  Employees (id, Name);  Positions (id, Post, Rate); EmployeesPositions - 我不知道如何做对。

我需要什么:将员工添加到"Employees"表时,将条目与"Positions"表中的帖子相关联,但正如我上面所写,一名员工可以与2个帖子相关联(但是不总是)。如何正确实现第三个表(EmployeesPositions),因为在Positions中只存储帖子和费率,而在EmployeesPositions中应该有记录,例如,Name1 => Post1和Post2,Name2只发布1?

如果我认为有问题,请告诉我如何最好地实施它。

1 个答案:

答案 0 :(得分:2)

有几种方法可以解决您的问题,每种方法各有利弊。

首先,如果我们将您的问题简化为“员工有零个或多个职位”,那么您可以使用下表将员工与职位相关联:

create table employeespositions (
    employee_id integer not null,
    position_id integer not null,
    constraint pk_employeespositions 
        primary key (employee_id, position_id),
    constraint fk_employeespositions_employee 
        foreign key (employee_id) references employees (id),
    constraint fk_employeespositions_position 
        foreign key (position_id) references positions (id)
)

外键强制存在员工和职位,而主键确保员工和职位的组合仅存在一次。

此解决方案有两个缺点:

  1. 不强制员工至少有一个职位
  2. 它允许员工拥有两个以上的职位
  3. 第二个问题很容易通过添加一个触发器来解决,该触发器在尝试插入时检查员工是否最多有1个位置(这允许最多两个):

    create exception tooManyPositions 'Too many positions for employee';
    
    set term #;
    recreate trigger employeespositions_bi 
        active before insert on employeespositions
    as
        declare position_count integer;
    begin
        select count(*) 
            from employeespositions 
            where employee_id = new.employee_id 
            into position_count;
        if (position_count > 1) then
            exception tooManyPositions;
    end#
    set term ;#
    

    但是,此解决方案并未强制员工至少拥有一个职位。您可以添加before delete触发器,以确保无法删除最后一个位置,但这并不能确保新创建的员工至少有一个职位。如果要强制执行,可能需要考虑使用存储过程来插入和更新员工及其职位,并让这些存储过程的代码强制执行(例如,在创建员工时要求职位)。

    或者,您也可以考虑对您的设计进行非规范化,并使该职位成为employees记录的一部分,其中员工具有“主要”和(可选)“次要”职位。

    create table employees (
        -- using Firebird 3 identity column, change if necessary
        id integer generated by default as identity primary key,
        name varchar(100),
        primary_position_id integer not null,
        secondary_position_id integer,
        constraint fk_employees_primary_position 
            foreign key (primary_position_id) references positions (id),
        constraint fk_employees_secondary_position 
            foreign key (secondary_position_id) references positions (id),
        constraint chk_no_duplicate_position 
            check (secondary_position_id <> primary_position_id)
    )
    

    not null上的primary_position_id约束强制存在此位置,而检查约束则阻止将相同位置分配给两列。或者,您可以考虑添加before insert or update触发器,在设置primary_position_id null时,将其设置为secondary_position_id的值,并将secondary_position_id设置为{{1} }}

    此解决方案的优点是允许强制执行主要位置,但在查询位置时可能会导致额外的复杂性。创建视图可以克服这个缺点:

    null

    然后可以将此视图用作表格(尽管您无法插入其中)。