我既是 SQL 数据库设计师又是应用程序程序员。
现在你有这样的东西。
create table users (
user_id integer primary key,
user_name varchar(35) not null unique
);
create table teams (
team_id integer primary key,
team_name varchar(35) not null unique
);
下表实现了每个用户最多可以是一个团队的成员的当前要求。(我假设某些用户可能不是任何团队的成员,可能只是在他们被雇用和他们报告工作的时间之间。)
create table team_members (
user_id integer primary key references users (user_id),
team_id integer not null references teams (team_id)
);
当该要求发生变化时,您需要允许用户成为多个团队的成员,您只需将主键从 {user_id} 更改为 {user_id, team_id}。应用程序代码根本不必更改。(但请参阅下面的“记录分歧”。)
您想像这样实现团队成员资格。
create table users (
user_id integer primary key,
user_name varchar(35) not null unique,
team_id integer null references teams (team_id)
);
如果这样做,您仍应实现团队成员视图,并且应用程序代码应使用该视图。根据您的应用程序,您可能需要将此视图设为可更新视图。
create view team_members as
select user_id, team_id
from users;
这是因为将团队成员身份放入用户表会破坏该表的谓词。它不再是一张用户表;这是一个用户表和他们的团队成员。所以“用户”这个名字是不准确的;它需要一个像“users_and_team_membership”这样的名字。(在数据的关系模型和 SQL 中,表名是变量的名称,默认情况下它们是数据库公共 API 的一部分。这里的工作原则是“不要评论坏代码。重写它。 ")
但是,无论您是修复表名还是将其保留为具有误导性的名称“users”,您都只是将一团糟变成了两团。“二”,因为 1) 一个表存储两种不同类型的数据,并且因为 2) 您要么使用准确的名称而丢失表“users”,要么使用具有误导性的名称并保留表“users”。
记录分歧
您还应该通过记录这种分歧来防止您的应用程序程序员做错事。像“假设用户只是一个团队的成员是未经检查的运行时错误”这样的语句就足够了。
YAGNI 在数据库设计和开发中的含义与它在应用程序开发中的含义并不完全相同。应用程序开发人员查看他们的代码并查看一个数据库。数据库设计人员查看他们的数据库,发现数十年来用数十种不同语言编写的数百个程序,他们计算了编写糟糕的公共 API 的成本。修复一个糟糕的公共 API 可能需要对数百个程序进行更改。这是很多钱。很多钱。