2010-10-08 7 views
8

Sto lavorando a un programma in cui è possibile registrare i reclami. Esistono tre tipi di reclami: internal (errori dei dipendenti), external (errori di un'altra azienda) e supplier (errori commessi da un fornitore). Contengono dati diversi che non possono essere condivisi. Al momento ho 4 tavoli (reclamo, dipendente, azienda e fornitore). Ecco una visualizzazione delle tabelle:Come si applicano i sottotipi in un database SQL Server?

Ho una conoscenza di base dei sottotipi ma non riesco a convertirli da un ERD in un vero database SQL Server, o almeno in questo scenario. Questo è più o meno come i 4 tavoli guardano (attributi irrilevanti omessi):

Reclamo
ComplaintId PK

dipendenti
EmployeeId PK
EmployeeName

impresa
CompanyID PK
CompanyName

Fornitore
IDFornitore PK
SupplierName

Quando si registra un reclamo, l'errore è fatto da uno dei 3 tipi e tutti memorizzare informazioni diverse. Qual è il modo migliore per memorizzare le informazioni in questo caso? Ho pensato di inserire 2 discriminatori nella tabella dei reclami: ComplaintType e Id in modo da poter indicare a quale tabella controllare e quale ID mi serve, ma non è molto pulito né efficiente.

Si prega di assistere.

risposta

4

Consiglio vivamente di NON utilizzare il metodo "2 discriminatori". Avrai effettivamente una colonna chiave esterna che punta a una delle tre tabelle, a seconda del campo ComplaintType. Se si esegue questa operazione, si bypassano i controlli di integrità referenziale forniti da SQL Server e tutti i vantaggi offerti dalle chiavi esterne. Al mio precedente lavoro, c'era una tabella chiamata EntityTypeIndexLabel che era una "tabella di bridge" che collegava IndexLabels (fondamentalmente metadati) a varie "entità", che erano molte diverse tabelle potenziali (Documento, Raccoglitore, Flusso di lavoro, ecc ...). Questo era semplicemente orribile. L'FK in questa tabella potrebbe indicare molte tabelle diverse. Record orfani potrebbero apparire ovunque. È necessario implementare una logica aggiuntiva per determinare su quale tabella partecipare. Le unire erano un dolore da scrivere in generale. C'erano tutti i tipi di mal di testa.

Credo che la vostra due opzioni sono:

-3 colonne nella denuncia: EmployeeComplaintID, CompanyComplaintID, SupplierComplaintID. I ComplaintID devono essere univoci in tutte le tabelle (si pensi ai GUID qui invece che alle colonne IDENTITY). Ogni riga in Complaint avrà solo uno di questi ID popolati, gli altri due saranno NULL. Quindi puoi semplicemente LEFT OUTER JOIN su queste tabelle in ogni query per ottenere i dati di cui hai bisogno.

-Una tavolo gigante con tutti i possibili campi necessari per ogni tipo di denuncia, i campi non utilizzati di altri tipi di reclamo a NULL.

+0

Grazie per il suggerimento; Starò sicuramente lontano dal metodo dei 2 discriminatori. Ho anche provato il metodo a 3 colonne ma non ancora con alcun tipo di vincolo. È possibile forzare almeno uno dei campi a non essere nullo? Se sì, come lo faresti? – Fusyion

+0

Ho scelto di accettare la risposta come 'la risposta' perché è informativo e ho scelto la prima opzione per far funzionare le cose. – Fusyion

+0

@ Mario Non vedo come una colonna ComplaintType e tre tabelle separate sarebbero un problema. Ciascuna delle tabelle figlio contiene una chiave esterna per la tabella padre. Vedere questo violino: http://sqlfiddle.com/#!3/6118b6/2 L'unico problema è che si potrebbe fare riferimento Parent sbagliato, il genitore di tipo incorect. Ma questo può essere risolto con un'introduzione di un ulteriore vincolo ed estensione delle chiavi esterne.Vedi questo violino: http://sqlfiddle.com/#!3/58cd0/1 Ma, come SQL Server spreca spazio nella memorizzazione di colonne Null vorrei andare con ine grande tabella per tutti i tipi e memorizzare valori nulli in colonne dove non applicabile. – Anderson

1

Il problema principale è che occorre una sorta di "numero di serie" per identificare in modo univoco un reclamo indipendentemente dal tipo? Fondamentalmente, quindi, hai bisogno di una tabella per ogni tipo di reclamo (come avrai, credo), più la tabella principale "Reclamo" con il Reclamo. Ciascuna delle tabelle specifiche del tipo avrà una chiave esterna per Complaint.ComplaintId. Potresti trovare utile avere un campo "tipo" in Reclamo, ma ciò non è realmente necessario per il modello.

+0

ho considerato avere tabelle separate per ogni tipo di reclamo, ma ci sono semplicemente troppi attributi in ogni tabella che sono ridondanti. – Fusyion

+0

successivamente, inserire questi attributi nella tabella principale "esposto", mettendo solo gli elementi univoci in ciascuna delle tabelle più specifici. – Andrew

1

È possibile avere un reclamoSubTypeID con una relazione FK al PK di tutte e tre le tabelle del sottotipo (dipendente, azienda e fornitore).

+0

Ho provato questo, ma non significa all'ID inserito nella tabella Reclamo deve corrispondere quella di tutti e tre i ** ** le tabelle? – Fusyion

+0

no, uno dei tre. l'assunto è che i tasti si escludano a vicenda. – Beth

+0

Allora devo fare qualcosa di sbagliato. Ho creato un 'SubTypeId' nella mia tabella dei reclami e ho creato una relazione con le chiavi primarie di tutte e tre le tabelle. Non sono riuscito a inserire alcun ID tranne quello che è lo stesso su tutti e tre i tavoli. – Fusyion

13

vedere alcune davvero buone risorse sul tema:

C'è fondamentalmente tre approcci ben noti:

  • tabella per sottoclasse
  • tabella per ogni Gerarchia
  • tabella per ogni tipo concreto

Ognuno ha vantaggi e svantaggi, brilla in qualche situazione e succhia in altri - studiare le risorse e vedere quale dei tre adatta alle vostre esigenze il migliore.

0

In risposta alla prenotazione Sei commento alla risposta accettata:

Qui di seguito è un modo per avere un controllo di controllo per assicurare che solo uno dei tre tasti dispone di dati:

alter table complaint_master 
    add constraint loc_attribute_has_one_value 
    check ( 
     (case when complaint_employee is null then 0 else 1 end) + 
     (case when complaint_supplier is null then 0 else 1 end) + 
     (case when complaint_external is null then 0 else 1 end) = 1 
    );