Pregunta de diseño/modelado de la base de datos: ¿restricciones o sin restricciones?

StackOverflow https://stackoverflow.com/questions/1155058

  •  18-09-2019
  •  | 
  •  

Pregunta

Dada la siguiente estructura:

City
Area
User

Cada área tiene 1 y solo 1 ciudad.
Cada usuario tiene al menos una pero posiblemente múltiples áreas.
Cada usuario tiene 1 y solo 1 ciudad.

¿Cuál es la forma más elegante de modelar esto?

Actualmente, tengo:

User,
UserArea,
Area,
City

Donde el Userea es una relación de 1: M con usuario, y el área es 1: 1 con la ciudad.

El problema es este:

Un usuario puede tener 3 o 4 áreas bajo el modelo actual, pero 2 de las áreas podrían estar en la ciudad "1" y las otras 2 áreas podrían estar en la ciudad "2". Esta es una violación de las reglas comerciales.

¿Debería poner una restricción para evitar este tipo de cosas, o es un mejor enfoque para normalizar aún más para que este tipo de paradoja no sea posible? Si es así, ¿cómo se modela este sistema para que:

1 usuario = 1 ciudad;
1 área = 1 ciudad;
1 usuario = m áreas;

Gracias por tus ideas.

¿Fue útil?

Solución 7

Esta respuesta me fue proporcionada desde SQLServerCentral, y hace exactamente lo que estaba buscando. Hay una redundancia (como señaló Rexum en este foro), pero no hay posibilidad de anomolías.

Estoy muy interesado en sus comentarios y sugerencias.


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

Otros consejos

Tendría una tabla cada uno para usuarios, áreas y ciudades, luego tendría una cuarta tabla con el usuario de columnas (FK), las ciudades (FK) y las áreas (FK) donde los usuarios y las ciudades (en combinación) se limitan a ser únicos. Luego, cada vez que se inserta una combinación de área de usuario, no permitirá una ciudad no unique.

Lo único que se me ocurre es:

Dé a la tabla de área una llave alternativa compuesta de Cityid y AreaID. Haga que AREAID sea primaria (para que solo pueda tener una ciudad).

Use esta clave alternativa (AK1) para formar una relación FK entre el área y el userea.

Ofrezca a la tabla de usuario una clave alternativa compuesta de UserID y CityID. Haga que UserID sea primario.

Use esta clave alternativa (AK2) para formar una relación FK entre el usuario y el usuario de usuario.

Entonces su tabla de usuarios se verá así:

UserID Cityid AreaId

El extranjero con sede en AK2 lo obligará a elegir una ciudad que coincida con la ciudad natal del usuario, y la clave externa con sede en AK1 lo obligará a elegir un área que pertenece a esa ciudad. En esencia, las claves extranjeras AK1 y AK2 se superpondrán, forzando lo que quieres.

Creo que su enfoque de "usuario, usuario, área, ciudad" es correcto. Confíe en las limitaciones y la lógica comercial para evitar violaciones.

¿Puede proporcionar más detalles sobre qué es un área? Déjame decir mis suposiciones:
El usuario vive en una ciudad.
Cada ciudad tiene áreas.
Un área puede caer en una sola ciudad.
Un usuario puede vivir en una sola ciudad
Dadas estas condiciones, parece tener las siguientes dependencias funcionales en su especificación de diseño:
Área -> Ciudad
Usuario -> Ciudad
Su modelo de negocio sugiere que el usuario puede tener múltiples direcciones dentro de la misma ciudad, pero no puede tener una dirección en dos ciudades diferentes. ¿Es esta una restricción de diseño realista? Si puedo tener múltiples direcciones, ¿por qué no en diferentes ciudades?
Si desea almacenar todas las áreas de un usuario determinado, necesita una tercera tabla (como ha sugerido). La mesa se vería como
UserAea (UserId, AreaId). Debe implementar la lógica comercial utilizando un disparador o un procedimiento almacenado.

USER_AREAS Solo requiere las siguientes columnas:

  • USER_ID (PK, FK para USERS.USER_ID)
  • AREA_ID (PK, FK para AREA.AREA_ID)

Un área está asociada a una ciudad en la tabla de áreas; Sabes qué ciudades están asociadas con el usuario al rodar de la tabla de áreas:

AREA

  • AREA_ID (paquete)
  • CITY-ID (FK para CITY.CITY_ID)

Poniendo CITY_ID en el USER_AREAS La mesa es redundante. En segundo lugar, colocando CITY_ID en el USER_AREAS La tabla no garantiza que el AREA_ID en ese registro se asocia en realidad con el CITY_ID en la mesa del área. Una restricción de verificación solo impone la integridad del dominio al limitar los valores que aceptan una columna, y no pueden referencia a las columnas en otras tablas deben menos una función definida por el usuario.

No puede hacer cumplir la regla comercial de las áreas de un usuario que solo pertenecen a una sola ciudad en la base de datos. Tendría que hacerse a nivel de aplicación (lo que SPROC administre la inserción/actualización de la USER_AREAS mesa).

No estoy seguro de a qué te refieres con "áreas".

Creo que la división urbana es la siguiente:

El planeta tiene países. Un país tiene regiones (estados, provincias, etc.) las regiones tienen áreas (ciudades, pueblos, pueblos, etc.), las áreas (si lo suficientemente grandes) pueden tener distritos.

Usuario => País + Región/Área + Ciudad ( + Distrito)

¿Podrías elaborar las áreas?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top