鉴于以下结构:
City
Area
User
每个区域都有1个且只有1个城市 每个用户至少有一个但可能有多个区域 每个用户只有1个城市。
对此进行建模的最优雅方式是什么?
目前,我有:
User,
UserArea,
Area,
City
其中UserArea与用户的1:M关系,与City的区域为1:1。
问题在于:
用户在当前模型下可以有3个或4个区域,但其中2个区域可以在城市“1”中,其他2个区域可以在城市“2”中。这违反了业务规则。
我应该只是设置一个约束来防止这种事情,还是一种更好的方法来进一步规范化,以便这种类型的悖论是不可能的?如果是这样,那么如何对该系统进行建模:
1个用户= 1个城市;
1区= 1城市;
1个用户= M个区域;
感谢您的见解。
答案 0 :(得分:1)
我将为用户,区域和城市分别提供一个表格,然后有第四个表格,其中包括列用户(FK),城市(FK)和区域(FK),其中Users&城市(组合)被限制为独特。然后,只要插入用户区组合,就不允许使用非唯一城市。
答案 1 :(得分:0)
我唯一能想到的就是:
为Area表提供CityID和AreaID的复合备用键。使AreaID成为主要的(因此它只能有一个城市)。
使用此备用键(AK1)在Area和UserArea之间形成FK关系。
为User表提供UserID和CityID的复合备用键。将UserID设为主要。
使用此备用密钥(AK2)在User和UserArea之间形成FK关系。
所以你的UserArea表将如下所示:
用户名 CityID areaID表示
基于AK2的外键将强制您选择与用户所在城市相匹配的城市,而基于AK1的外键将强制您选择属于该城市的区域。实质上,AK1和AK2外键会重叠,强制你想要的东西。
答案 2 :(得分:0)
我认为您的“用户,用户区域,区域,城市”方法是正确的。依靠约束和业务逻辑来防止违规。
答案 3 :(得分:0)
您能否提供有关区域的更多详细信息?让我说出我的假设:
用户住在城市。
每个城市都有区域
一个区域只能落入一个城市
用户只能住在一个城市
鉴于这些条件,您似乎在设计规范中具有以下功能依赖性:
面积 - >市
用户 - >市
您的商业模式表明,用户可以在同一城市内拥有多个地址,但不能在两个不同的城市拥有地址。这是一个现实的设计约束吗?如果我可以有多个地址,为什么不在不同的城市呢?
如果要存储给定用户的所有区域,则需要第三个表(如您所建议的那样)。该表看起来像是UserArea(userID,AreaID)。您需要使用触发器或存储过程来实现业务逻辑。
答案 4 :(得分: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_ID
放在USER_AREAS
表中是多余的。其次,将CITY_ID
放在USER_AREAS
表中并不能保证该记录中的AREA_ID
实际上与AREA表中的CITY_ID
相关联。 CHECK约束仅通过限制列接受的值来强制域完整性,并且不能引用其他表中的列必须少于用户定义的函数。
您无法强制执行仅属于数据库中单个城市的用户区域的业务规则。它必须在应用程序级别完成(无论sproc管理插入/更新USER_AREAS
表)。
答案 5 :(得分:0)
我不确定“区域”是什么意思。
我认为城市区划如下:
这个星球有国家。 一个国家有地区(州,省等) 地区有地区(城市,城镇,村庄等) 区域(如果足够大)可以有区域。
用户=>国家+地区/地区+城市(+地区)
请您详细说明一下?
答案 6 :(得分:0)
这个答案是从SQLServerCentral提供给我的,它完全符合我的要求。存在冗余(正如本论坛中指出的那样),但不存在异常现象。
我对你的意见和建议很感兴趣。
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])