Pergunta

Dada a seguinte estrutura:

City
Area
User

Cada área tem 1 e apenas 1 cidade.
Todo usuário tem pelo menos um, mas possivelmente várias áreas.
Todo usuário tem 1 e apenas 1 cidade.

Qual é a maneira mais elegante de modelar isso?

Atualmente, eu tenho:

User,
UserArea,
Area,
City

Onde a UserAea é um relacionamento 1: M com usuário e a área é 1: 1 com a cidade.

O problema é o seguinte:

Um usuário pode ter 3 ou 4 áreas sob o modelo atual, mas duas das áreas podem estar na cidade "1" e as outras duas áreas podem estar na cidade "2". Esta é uma violação das regras de negócios.

Devo apenas colocar uma restrição para evitar esse tipo de coisa ou é uma abordagem melhor para normalizar ainda mais para que esse tipo de paradoxo não seja possível? Nesse caso, como um modela este sistema para que:

1 usuário = 1 cidade;
1 área = 1 cidade;
1 usuário = m áreas;

Obrigado por suas idéias.

Foi útil?

Solução 7

This answer was provided to me from SQLServerCentral, and it does exactly what I was looking for. There is a redundancy (as rexum pointed out in this forum), but there is no possibility of anomolies.

I'm very interested in your comments and suggestions.


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])

Outras dicas

Eu teria uma tabela cada um para usuários, áreas e cidades e, em seguida, uma quarta mesa com colunas Usuário (FK), cidades (FK) e áreas (FK), onde os usuários e cidades (em combinação) são restringidos para serem únicos. Então, sempre que uma combinação de área de usuário é inserida, ela não permitirá uma cidade não única.

A única coisa que consigo pensar em inchaço é:

Dê à tabela de área uma chave alternativa composta do CityID e da área. Faça do AreaID primário (para que ele possa ter apenas uma cidade).

Use essa chave alternativa (AK1) para formar uma relação FK entre área e usuário.

Dê à tabela de usuários uma chave alternativa composta do UserID e CityID. Tornar o userID primário.

Use essa chave alternativa (AK2) para formar uma relação FK entre usuário e usuário.

Então, sua tabela de usuário ficará assim:

UserID CityId AreaID

A chave estrangeira baseada em AK2 o forçará a escolher uma cidade que corresponda à cidade natal do usuário, e a chave estrangeira baseada em AK1 o forçará a escolher uma área que pertence a essa cidade. Em essência, as chaves estrangeiras AK1 e AK2 se sobreporão, forçando o que você deseja.

Eu acho que sua abordagem "usuário, usuário, área, cidade" está correta. Confie nas restrições e na lógica de negócios para evitar violações.

Você pode fornecer mais detalhes sobre o que é uma área? Deixe -me declarar minhas suposições:
O usuário vive em uma cidade.
Toda cidade tem áreas.
Uma área pode cair apenas em uma cidade.
Um usuário pode viver apenas em uma cidade
Dadas essas condições, você parece ter as seguintes dependências funcionais em suas especificações de design:
Área -> Cidade
Usuário -> Cidade
Seu modelo de negócios sugere que o usuário pode ter vários endereços na mesma cidade, mas não pode ter um endereço em duas cidades diferentes. Isso é uma restrição de design realista? Se eu posso ter vários endereços, por que não em diferentes cidades?
Se você deseja armazenar todas as áreas de um determinado usuário, precisa de uma terceira tabela (como sugeriu). A mesa seria como
UserAea (UserID, AreaID). Você precisa implementar a lógica de negócios usando um gatilho ou um procedimento armazenado.

USER_AREAS only requires the following columns:

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

An area is associated to one city in the AREAS table; you know which cities are associated with the user by rolling up from the AREAS table:

AREA

  • AREA_ID (pk)
  • CITY-ID (fk for CITY.CITY_ID)

Putting CITY_ID in the USER_AREAS table is redundant. Secondly, placing CITY_ID in the USER_AREAS table does not guarantee that the AREA_ID in that record is actually associated with the CITY_ID in the AREA table. A CHECK constraint only enforces domain integrity by limiting the values that are accepted by a column, and can not reference columns in other tables must less a user defined function.

You can't enforce the business rule of a user's areas only ever belonging to a single city in the database. It would have to be done at the application level (whatever sproc manages inserting/updating the USER_AREAS table).

I'm not sure what you mean by "areas".

I believe the urban division is as follows:

The planet has countries. A country has regions (states, provinces etc.) Regions have areas (cities, towns, villages etc.) Areas (if big enough) can have districts.

User => Country + Region/Area + City (+ District)

Could you please elaborate on areas?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top