我是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?
如果我认为有问题,请告诉我如何最好地实施它。
答案 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个位置(这允许最多两个):
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
然后可以将此视图用作表格(尽管您无法插入其中)。