2010-12-23 17 views
6

tengo una tabla llamada como PartyChannel teniendo siguientes columnasclave externa condicional en SQL

ID, ChannelID, ChannelType 

ChannelID almacena MailID o PhoneID o EmailID dependiendo de la ChannelType.

Entonces, ¿cómo puedo crear una clave foránea entre PartyChannel y las tres tablas (Correo, Correo electrónico y Teléfono) dependiendo del channelType.

+3

MailID, PhoneID, EMAILID son tres dominios distintos y no pueden, no deben ser modelado utilizando una única columna de channelId. Esto es algo fundamental. – onedaywhen

Respuesta

4

AFAIK, no puede hacer esto con claves externas estándar. Sin embargo, podría implementar algo para ayudar a garantizar la integridad de los datos mediante el uso de activadores. Básicamente, el activador verificaría la presencia de una "clave externa" en la tabla referenciada, el valor que debe estar presente, siempre que haya una inserción o actualización en la tabla de referencia. Del mismo modo, una eliminación de la tabla a la que se hace referencia podría tener un activador que verifique los registros en la tabla de referencia que utiliza la clave que se elimina.

Actualización: Aunque fui directo a la "respuesta", estoy de acuerdo con el comentario dejado por @oneday cuando se trata de un problema causado por el diseño que probablemente debería hacer reconsiderar su diseño. Es decir, debe tener tres columnas diferentes en lugar de una columna que haga referencia a tres tablas. Simplemente dejaría las otras dos columnas nulas cuando se llene una que, a su vez, le permitiría usar claves externas estándar. Cualquier preocupación de que esto "use demasiado espacio" es una tontería; representa un caso severo de optimización prematura, simplemente no va a importar.

7

Puede usar las columnas PERSISTED COMPUTED con una declaración de caso, pero al final, no le compra nada más que gastos generales.

La mejor solución sería modelarlos como tres valores distintos para empezar.

CREATE TABLE Mails (MailID INTEGER PRIMARY KEY) 
CREATE TABLE Phones (PhoneID INTEGER PRIMARY KEY) 
CREATE TABLE Emails (EmailID INTEGER PRIMARY KEY) 

CREATE TABLE PartyChannel (
    ID INTEGER NOT NULL 
    , ChannelID INTEGER NOT NULL 
    , ChannelType CHAR(1) NOT NULL 
    , MailID AS (CASE WHEN [ChannelType] = 'M' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Mails (MailID) 
    , PhoneID AS (CASE WHEN [ChannelType] = 'P' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Phones (PhoneID) 
    , EmailID AS (CASE WHEN [ChannelType] = 'E' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Emails (EmailID) 
) 

Negación

sólo porque puede no significa que usted debe.

+0

Esto es bastante salvaje. ¿Funciona en todas las principales implementaciones de SQL? –

+0

@Mark: funciona con SQL Server 2005 y 2008. Aparte de eso, sinceramente no tengo ni idea, fue un buen ejercicio mental . Sin embargo, un descargo de responsabilidad podría estar en orden: * ¡solo porque no puede significar que debe hacerlo! * –

+0

Funciona en SQL Server aunque su ChannelType debe ser un char o varchar en lugar de un int. Nuevamente - +1 - gracias. Cosas bastante interesantes e inusuales. Todavía estoy de acuerdo con @oneday cuando este no es un buen diseño, pero agradezco la lección de SQL poco convencional que me has proporcionado. –

4

Subtipo Email, Mail, Phone al Channel.

alt text

+0

Este es el patrón gen-spec, como se representa en un modelo relacional. El diagrama ilustra las llaves muy bien. Buen trabajo. –

Cuestiones relacionadas