1

给定以下结构:

City
Area
User

每个区域有 1 个且只有 1 个城市。
每个用户至少有一个但可能有多个区域。
每个用户有 1 个且只有 1 个城市。

建模这个最优雅的方法是什么?

目前,我有:

User,
UserArea,
Area,
City

其中 UserArea 是与 User 的 1:M 关系,Area 与 City 是 1:1 的关系。

问题是这样的:

在当前模型下,用户可以拥有 3 或 4 个区域,但其中 2 个区域可能位于城市“1”,另外 2 个区域可能位于城市“2”。这是违反业务规则的。

我应该设置一个约束来防止这种事情发生,还是一种更好的方法来进一步规范化,这样这种悖论就不可能发生?如果是这样,如何对该系统进行建模,以便:

1 个用户 = 1 个城市;
1 个地区 = 1 个城市;
1 个用户 = M 个区域;

感谢您的见解。

4

7 回答 7

1

我将为用户、区域和城市分别创建一个表,然后有第四个表,其中包含用户(FK)、城市(FK)和区域(FK)列,其中用户和城市(组合)被限制为唯一。然后,每当插入用户区域组合时,它就不允许非唯一的城市。

于 2009-07-20T18:32:19.000 回答
0

我能想到的唯一一件事是:

为 Area 表提供 CityID 和 AreaID 的复合备用键。将 AreaID 设为主要(因此它只能有一个城市)。

使用此备用密钥 (AK1) 在 Area 和 UserArea 之间形成 FK 关系。

为 User 表提供一个由 UserID 和 CityID 组成的复合备用键。将 UserID 设为主要。

使用此备用密钥 (AK2) 在 User 和 UserArea 之间形成 FK 关系。

因此,您的 UserArea 表将如下所示:

UserID CityID AreaID

基于 AK2 的外键将强制您选择与用户的家乡城市匹配的城市,基于 AK1 的外键将强制您选择属于​​该城市的区域。本质上,AK1 和 AK2 外键会重叠,强制你想要什么。

于 2009-07-20T18:39:39.937 回答
0

我认为您的“用户,用户区域,区域,城市”方法是正确的。依靠约束和业务逻辑来防止违规。

于 2009-07-20T22:45:16.900 回答
0

你能提供更多关于什么是区域的细节吗?让我陈述我的假设:
用户住在一个城市。
每个城市都有区域。
一个地区只能落入一个城市。
一个用户只能住在一个城市
鉴于这些条件,您的设计规范中似乎具有以下功能依赖关系:
区域 -> 城市
用户 -> 城市
您的业务模型表明用户可以在同一个城市内拥有多个地址,但不能在两个不同的城市有一个地址。这是一个现实的设计约束吗?如果我可以有多个地址,那为什么不在不同的城市呢?
如果要存储给定用户的所有区域,则需要第三张表(如您所建议的那样)。桌子看起来像
用户区域(用户 ID,区域 ID)。您需要使用触发器或存储过程来实现业务逻辑。

于 2009-07-26T06:23:44.340 回答
0

USER_AREAS只需要以下列:

  • USER_ID(pk, fk 为USERS.USER_ID)
  • AREA_ID(pk, fk 为AREA.AREA_ID)

一个区域与 AREAS 表中的一个城市相关联;您可以通过 AREAS 表中的滚动了解哪些城市与用户相关联:

AREA

  • AREA_ID(PK)
  • CITY-ID(fk 为CITY.CITY_ID)

放在桌子CITY_IDUSER_AREAS是多余的。其次,放置CITY_IDUSER_AREAS表中并不能保证该AREA_ID记录中的实际与CITY_IDAREA 表中的 相关联。CHECK 约束仅通过限制列接受的值来强制域完整性,并且不能引用其他表中的列,必须少用户定义的函数。

您不能强制执行仅属于数据库中单个城市的用户区域的业务规则。它必须在应用程序级别完成(无论 sproc 管理插入/更新USER_AREAS表)。

于 2009-07-26T21:01:08.740 回答
0

我不确定您所说的“区域”是什么意思。

我认为城市划分如下:

这个星球有国家。一个国家有地区(州、省等)。地区有地区(城市、城镇、村庄等)。地区(如果足够大)可以有地区。

用户 => 国家 + 地区/地区 + 城市(+ 区)

能详细说明一下地区吗?

于 2009-07-26T21:07:22.160 回答
0

这个答案是从 SQLServerCentral 提供给我的,它完全符合我的要求。存在冗余(正如 rexum 在本论坛中指出的那样),但不可能出现异常。

我对您的意见和建议非常感兴趣。


CREATE TABLE [dbo].[Cities](
    [CityID] [int] IDENTITY(1,1) NOT NULL,
  [CityName] [varchar](50) NOT NULL,
 CONSTRAINT [PK_Cities] PRIMARY KEY CLUSTERED
(
   [CityID] ASC
)
)
CREATE TABLE [dbo].[Users](
   [UserID] [int] IDENTITY(1,1) NOT NULL,
  [UserName] [varchar](50) NOT NULL,
  [CityID] [int] NOT NULL,
 CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED
(
  [UserID] ASC
)
)

ALTER TABLE [dbo].[Users]  WITH CHECK ADD  CONSTRAINT [FK_Users_Cities] FOREIGN KEY([CityID])
REFERENCES [dbo].[Cities] ([CityID])
GO
ALTER TABLE [dbo].[Users] CHECK CONSTRAINT [FK_Users_Cities]
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_UsersCity] ON [dbo].[Users]
(
   [UserID] ASC,
   [CityID] ASC
)

CREATE TABLE [dbo].[Areas](
    [AreaID] [int] IDENTITY(1,1) NOT NULL,
  [AreaName] [varchar](50) NOT NULL,
  [CityID] [int] NOT NULL,
 CONSTRAINT [PK_Areas] PRIMARY KEY CLUSTERED
(
  [AreaID] ASC
))


GO
ALTER TABLE [dbo].[Areas]  WITH CHECK ADD  CONSTRAINT [FK_Areas_Cities] FOREIGN KEY([CityID])
REFERENCES [dbo].[Cities] ([CityID])
GO
ALTER TABLE [dbo].[Areas] CHECK CONSTRAINT [FK_Areas_Cities]
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_AreasCity] ON [dbo].[Areas]
(
 [AreaID] ASC,
   [CityID] ASC
)
GO
CREATE TABLE [dbo].[UserCityArea](
   [UserID] [int] NOT NULL,
    [CityID] [int] NOT NULL,
    [AreaID] [int] NOT NULL,
 CONSTRAINT [PK_UserCityArea] PRIMARY KEY CLUSTERED
(
   [UserID] ASC,
   [CityID] ASC,
   [AreaID] ASC
)
)

GO
ALTER TABLE [dbo].[UserCityArea]  WITH CHECK ADD FOREIGN KEY([UserID], [CityID])
REFERENCES [dbo].[Users] ([UserID], [CityID])
GO
ALTER TABLE [dbo].[UserCityArea]  WITH CHECK ADD FOREIGN KEY([AreaID], [CityID])
REFERENCES [dbo].[Areas] ([AreaID], [CityID])
于 2009-07-27T16:41:53.600 回答