Tengo tres tablas: Customers, Providers y Locations. Necesito crear una cuarta tabla llamada Contacts.

Me gustaría tener cualquier número de Contacts asociado con cualquier fila en la tabla Customers, Providers y Locations, así que terminé con algo como esto.

CREATE TABLE [dbo].[Contacts] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [CustomerId] INT            NULL,
    [ProviderId] INT            NULL,
    [LocationId] INT            NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL,
);

No me parece muy elegante. Además de tener columnas no utilizadas, probablemente debería agregar una restricción para asegurar que exactamente una de CustomerId, ProviderId y LocationId no sean NULL.

Otra alternativa es crear una tabla de unión de muchos a muchos. Esto no necesitará ninguna columna no utilizada. Pero todavía parece un desperdicio ya que ningún contacto se relacionará con más de una compañía.

¿Alguien sabe de alguna solución ingeniosa?

1
Jonathan Wood 26 may. 2020 a las 01:55

3 respuestas

La mejor respuesta

Una alternativa sería revertir la relación y crear una tabla de mapeo para cada entidad con la que un contacto pueda relacionarse, como:

CREATE TABLE [dbo].[Contacts] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL
);

CREATE TABLE [dbo].[ContactCustomers] ( 
    [ContactId]  INT NOT NULL REFERENCES Contacts([ContactId]),
    [CustomerId] INT NOT NULL REFERENCES Customers([CustomerId]),
    PRIMARY KEY([ContactId], [CustomerId])
);

CREATE TABLE [dbo].[ContactProviders] ( 
    [ContactId]  INT NOT NULL REFERENCES Contacts([ContactId]),
    [ProviderId] INT NOT NULL REFERENCES Providers([ProviderId]),
    PRIMARY KEY([ContactId], [ProviderId])      
);

CREATE TABLE [dbo].[ContactLocations] ( 
    [ContactId]  INT NOT NULL REFERENCES Contacts([ContactId]),
    [LocationId] INT NOT NULL REFERENCES Locations([LocationId]),
    PRIMARY KEY([ContactId], [LocationId])      
);

Esto le brinda la flexibilidad total en términos de relaciones, mientras mantiene la tabla Contacts enfocada en su propósito principal: almacenar los datos relacionados con esta entidad.

1
GMB 25 may. 2020 a las 23:03

Contactos es una generalización de clientes, proveedores y ubicaciones. Hay un par de técnicas que puede encontrar útiles aquí. y .

0
Walter Mitty 27 may. 2020 a las 09:57

Además de la sugerencia de @ GMB, la otra alternativa es simplemente tener diferentes tablas de contactos. El hecho de que las ubicaciones y los clientes tengan contactos, y solo porque inicialmente tengan los mismos atributos, no significa que tengan que almacenarse en la misma tabla.

Es más eficiente almacenarlos por separado de esta manera, si no va a consultar todos los contactos. Y el esquema para los tres puede divergir con el tiempo.

Incluso podrían compartir una superclase NotMapped de contacto en la aplicación, si desea escribir una lógica común sobre los tipos de contacto.

P.EJ

CREATE TABLE [dbo].[CustomerContacts] (
    [CustomerId] INT            not null references Customer on delete cascade,
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL,
    constraint pk_CustomerContacts primary key (CustomerId,Id)
);
CREATE TABLE [dbo].[ProviderContacts] (
    [ProviderId] INT            not null references Provider on delete cascade,
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL,
    constraint pk_ProviderContacts primary key (ProviderId,Id)
);
CREATE TABLE [dbo].[LocationContacts] (
    [LocationId] INT            not null references Location on delete cascade,
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (80)  NULL,
    [Email]      NVARCHAR (80)  NULL,
    [Phone]      NVARCHAR (80)  NULL,
    [Title]      NVARCHAR (80)  NULL,
    [Address]    NVARCHAR (120) NULL,
    constraint pk_LocationContacts primary key (LocationId,Id)
);
1
David Browne - Microsoft 26 may. 2020 a las 13:30