2010-10-20 12 views
5

Aquí hay una pregunta difícil de normalización/SQL/Diseño de bases de datos que nos ha estado confundiendo. Espero poder decirlo correctamente.¿Cuál es la mejor manera de diseñar este problema particular de base de datos/SQL?

Tiene un conjunto de actividades. Son cosas que deben hacerse, una lista glorificada TODO. Cualquier actividad dada se puede asignar a un empleado.

Cada actividad también tiene una entidad para la cual se realizará la actividad. Esas actividades son un Contacto (persona) o un Cliente (empresa). Cada actividad tendrá un Contacto o un Cliente para quien se realizará la actividad. Por ejemplo, la actividad podría ser "Enviar una tarjeta de agradecimiento a Spacely Sprockets (un cliente)" o "Enviar literatura de marketing a Tony Almeida (un contacto)".

De esa estructura, entonces necesitamos ser capaces de consulta para encontrar todas las actividades de un determinado empleado tiene que hacer, a enumerarlos en una única relación que sería algo como esto en ella forma más simple:

----------------------------------------------------- 
| Activity | Description | Recipient of Activity | 
----------------------------------------------------- 

La idea aquí es evitar tener dos columnas para Contacto y Cliente con una de ellas nula.

Espero haberlo descrito correctamente, ya que esto no es tan obvio como podría parecer a primera vista.

Entonces la pregunta es: ¿Cuál es el diseño "correcto" para la base de datos y cómo lo consultaría para obtener la información solicitada?

+0

Parece haber cierta confusión acerca de los clientes y contactos. ¿Son tablas separadas? ¿Hay alguna relación entre clientes y contactos? ¿Son tablas existentes con las que necesita trabajar o tablas nuevas o refaccionables? – ulty4life

+0

Sí, los clientes y contactos son entidades separadas. Quizás no deberían serlo, pero lo son. ;-) –

Respuesta

2

Aquí es mi puñalada en ella:

Básicamente se necesitan actividades que se asocian a 1 (contacto o cliente) y 1 empleado que es ser una persona responsable de la actividad . Tenga en cuenta que puede manejar restricciones referenciales en un modelo como este.

También tenga en cuenta que agregué una tabla businessEntity que conecta todas las personas y lugares. (a veces útil pero no necesario). La razón para colocar la tabla businessEntity es que podría hacer referencia simple a ResponsiblePerson y al Receptor sobre la actividad en businessEntity y ahora puede tener actividades realizadas y recibidas por cualquier persona o lugar.

alt text

1

Se podría tener algo como sigue:

Activity | Description | Recipient Type

Dónde Recipient Type es uno de Contact o Customer

A continuación, ejecutar una instrucción de selección de SQL de la siguiente manera:
Select * from table where Recipient_Type = 'Contact';

Me doy cuenta de que tiene que haber más información.

Vamos a necesitar una tabla adicional que sea representativa de destinatarios (contactos y clientes):

Esta tabla debe tener el siguiente aspecto:

ID | Name| Recipient Type

Recipient Type habrá una referencia clave para la tabla inicialmente mencionado anteriormente en esta publicación. Por supuesto, será necesario trabajar para manejar cascadas en estas tablas, principalmente en actualizaciones y eliminaciones. Así que para recapitular rápidamente:

Recipients.Recipient_Type es una FK a Table.Recipient_Type

+1

¿Dónde dice quién es el destinatario en este modelo? ¿Cómo gestionará Foreign Keys a 'Contacts' /' Customers'? Harás una distinción entre estos? –

+0

No estoy seguro de seguir su pregunta Martin, veo ahora – Woot4Moo

+1

Esto debería ser más fluido y responder a la pregunta. Avíseme si necesita más explicación – Woot4Moo

4

El diseño "correcta" para esta base de datos es tener una columna para cada uno, que se dice que está tratando de evitar. Esto permite que se defina una relación de clave externa apropiada entre esas dos columnas y sus respectivas tablas. Usar la misma columna para una clave que hace referencia a dos tablas diferentes hará que las consultas sean feas y no se puede aplicar la integridad referencial.

mesa

Actividades debe tener las claves externas Contact ID, CustomerID

Para mostrar las actividades de los empleados:

SELECT ActivityName, ActivityDescription, CASE WHEN a.ContactID IS NOT NULL THEN cn.ContactName ELSE cu.CustomerName END AS Recipient 
FROM activity a 
LEFT JOIN contacts cn ON a.ContactID=cn.ContactID 
LEFT JOIN customers cu ON a.CustomerID=cu.CustomerID 
+0

Creo que hay un malentendido fundamental en lo que se refiere a una clave externa con respecto a una base de datos relacional de su lado. – Woot4Moo

+0

No estoy seguro de lo que quiere decir. Pude haber asumido lo que OP estaba proponiendo. –

+0

El problema que tomo en cuenta es el mismo que en la publicación con el bonito diagrama. ¿Cómo no se convierte esto en un problema de mantenimiento en el futuro a medida que se agregan más tipos de Destinatarios? La forma más adecuada, ver mantenible, es tener una tabla de Destinatarios que permita la adición/modificación de la columna Recipient_Type que no dañe drásticamente la psique de nadie que mantenga la base de datos. – Woot4Moo

9

Suena como una relación básica de muchos a muchos y me gustaría modelar como tal.

alt text

+0

¿Cómo funciona esta escala? a medida que se agregan más tipos de destinatarios, en términos de mantenimiento? – Woot4Moo

+0

Me gusta de muchas maneras, pero agrega dos tablas adicionales ... y una funcionalidad adicional. A menos que se necesite tener varios destinatarios para una sola actividad, pensar que tener dos claves foráneas en la tabla de actividades sería más simple. –

+0

@ Woot4Moo: Obviamente se escala requiriendo tablas adicionales, pero evita los problemas de cascada mencionados en su sol. ution. –

0
[ActivityRecipientRecipientType] 
    ActivityId 
    RecipientId 
    RecipientTypeCode 
     ||| ||| |||_____________________________  
     |  |         | 
     |  --------------------    | 
     |      |    | 
    [Activity]    [Recipient]  [RecipientType] 
    ActivityId    RecipientId  RecipientTypeCode 
    ActivityDescription  RecipientName RecipeintTypeName 


    select 
     [Activity].ActivityDescription 
    , [Recipient].RecipientName 
    from 
     [Activity] 
    join [ActivityRecipientRecipientType] on [Activity].ActivityId = [ActivityRecipientRecipientType].ActivityId 
    join [Recipient] on [ActivityRecipientRecipientType].RecipientId = [Recipient].RecipientId 
    join [RecipientType] on [ActivityRecipientRecipientType].RecipientTypeCode = [RecipientType].RecipientTypeCode 
    where [RecipientType].RecipientTypeName = 'Contact' 
+0

¿Le interesa explicar la necesidad de varias combinaciones y cómo esto no se convierte en la pesadilla de un DBA? – Woot4Moo

4

No es claro por qué se está definiendo clientes y contactos como entidades separadas, cuando parecen ser versiones de la misma entidad. Me parece que los Clientes son Contactos con información adicional. Si fuera posible, crearía una tabla de contactos y luego marcaría los que son clientes con un campo en esa tabla o agregando sus identificadores a una tabla Clientes que tienen la información de cliente singleton extendida en ella.

Si no puede hacer eso (porque esto se está construyendo sobre un sistema existente cuyo diseño es fijo), entonces tiene varias opciones. Ninguna de las opciones es buena porque realmente no puede solucionar el problema original, que es el almacenamiento de Clientes y Contactos por separado.

  1. Utilice dos columnas, una NULL, para permitir que funcione la integridad referencial.

  2. Cree una tabla intermedia ActivityContacts con su propia PK y dos columnas, una NULL, para señalar al Cliente o al Contacto. Esto le permite construir un sistema de Actividad "limpio", pero empuja la fealdad a esa tabla intermedia. (Proporciona un posible beneficio, que es que le permite limitar el objetivo de las actividades a personas agregadas a la tabla intermedia, si eso es una ventaja para usted).

  3. Lleve la falla de diseño original en el sistema de Actividades y (me estoy mordiendo la lengua aquí) tenga tablas paralelas de Actividad de Contacto y Cliente. Para encontrar todas las tareas asignadas a un empleado, UNE esas dos tablas juntas en una en una VISTA. Esto le permite mantener la integridad referencial, no requiere columnas NULL y le proporciona una fuente desde la cual obtener sus informes.

0
Actions 
Activity_ID | Description | Recipient ID 
------------------------------------- 
11 | Don't ask questions | 0 
12 | Be cool | 1 

Activities 
ID | Description 
---------------- 
11 | Shoot 
12 | Ask out 

People 
ID | Type | email | phone | GPS |.... 
------------------------------------- 
0 | Troll | [email protected]om | 232323 | null | ... 
1 | hottie | [email protected] | 2341241 | null | ... 


select at.description,a.description, p.* from Activities at, Actions a, People p 
where a."Recipient ID" = p.ID 
    and at.ID=a.activity_id 

result: 

Shoot | Don't ask questions | 0 | Troll | [email protected] | 232323 | null | ... 
Ask out | Be cool | 1 | hottie | [email protected] | 2341241 |null | ... 
1

alt text

2

Si he leído el caso derecha, destinatarios es una generalización de clientes y contactos.
El patrón de diseño gen-spec es bien entendido.

Data modeling question

0

Modelo otra entidad: ActivityRecipient, que será heredado por ActivityRecipientContact y ActivityRecipientCustomer, que ejercerá la debida atención al cliente/Contact ID.

Las tablas correspondientes serán:

Table: Activities(...., RecipientID) 

Table: ActivityRecipients(RecipientID, RecipientType) 

Table: ActivityRecipientContacts(RecipientID, ContactId, ...,ExtraContactInfo...) 

Table: ActivityRecipientCustomers(RecipentID, CustomerId, ...,ExtraCustomerInfo...) 

De esta manera también se puede tener diferentes otras columnas para cada tipo de destinatario

0

Me gustaría revisar esa definición de cliente y de contacto. Un cliente puede ser una persona o un negocio, ¿no? En Brasil, existen los términos "pessoa jurídica" y "pessoa física", que en una traducción directa (y sin sentido) se convierten en "persona jurídica" (empresa) y "persona física" (individual). Una mejor traducción fue sugerida por Google: 'entidad legal' e 'individuo'.

Por lo tanto, obtenemos una tabla de personas y tenemos una 'LegalEntity' y tablas 'individuales' (si hay suficientes atributos para justificarla, aquí hay muchas). Y el receptor se convierte en una mesa de FK a Persona.

¿Y dónde se han ido los contactos? Se convierten en una mesa que vincula a la persona. Dado que un contacto es una persona que está en contacto con otra persona (por ejemplo, mi esposa es mi contacto registrado en algunas empresas, soy cliente). La gente puede tener contactos.

Nota: Utilicé la palabra 'Persona' pero puede llamarla 'Cliente' para nombrar esa tabla base.

Cuestiones relacionadas