Domanda

In primo luogo, mi scuso se questa è una vittima -. Ho il sospetto che possa essere, ma io non riesco a trovarlo

Di 'Ho una tabella di aziende:

 id | company_name
----+--------------
  1 | Someone
  2 | Someone else

... e un tavolo di contatti:

 id | company_id | contact_name | is_primary
----+------------+--------------+------------
  1 |     1      | Tom          |      1
  2 |     2      | Dick         |      1
  3 |     1      | Harry        |      0
  4 |     1      | Bob          |      0

E 'possibile impostare la tabella contacts in modo tale che un richiede che una e una sola record ha il set is_primary bandiera per ogni company_id comune?

Quindi, se ho cercato di fare:

UPDATE contacts
SET is_primary = 1
WHERE id = 4

... la query fallirebbe, perché Tom (id = 1) è già contrassegnato come il contatto principale per company_id = 1. O meglio ancora, sarebbe possibile costruire un trigger in modo che la query avrebbe avuto successo, ma la bandiera Tom di is_primary sarebbe autorizzata dalla stessa operazione?

Io non sono troppo preoccupato di verificare se esiste company_id nella tabella companies, il mio codice PHP sarebbe già eseguito questo controllo prima di arrivare a questa fase (anche se c'è un modo per fare questo nella stessa operazione sarebbe bello, suppongo).

Quando ho inizialmente pensato a questo ho pensato "che sarà facile, ti basta aggiungere un indice univoco attraverso le colonne company_id e is_primary", ma, ovviamente, che non funzionerà come sarebbe mi limitare a uno primario e uno non contatto -Primary - qualsiasi tentativo di aggiungere un terzo contatto fallirebbe. Ma non posso fare a sensazione che ci sarebbe un modo per configurare un indice univoco che mi dà la funzionalità minima richiedo - a respingere un tentativo di aggiungere un secondo contatto primario, o rifiutare un tentativo di lasciare una società senza contatto principale.

Sono consapevole che ho potuto solo aggiungere un campo alla tavola primary_contact companies con FK al tavolo contacts ma ci si sente disordinato. Non mi piace l'idea di entrambe le tabelle hanno un FK per l'altro - mi sembra che l'una tabella dovrebbe fare affidamento sugli altri, non entrambe le tabelle basandosi sulla vicenda. Credo solo che nel corso del tempo non v'è più possibilità di qualcosa di sbagliato in corso.

Per riassumere:

  • Come posso limitare la tabella di contatti in modo che uno e un solo record con un dato company_id ha il set is_primary bandiera?
  • Qualcuno ha qualche idea su se due tabelle che hanno FKS gli uni agli altri è una buona / cattiva idea?
È stato utile?

Soluzione

refenences circolari tra tabelle sono davvero disordinato. Vedere questo (decennio vecchio) articolo: SQL By Design: The circolare Riferimento

Il modo più pulito di fare una tale vincolo è quello di aggiungere un altro tavolo:

Company_PrimaryContact
----------------------
company_id
contact_id
PRIMARY KEY (company_id)
FOREIGN KEY (company_id, contact_id)
  REFERENCES Contact (company_id, id)

Ciò richiederà anche un vincolo UNIQUE nella tabella Contact su (company_id, id)

Altri suggerimenti

Si può solo fare una query prima che un'impostazione

UPDATE contacts SET is_primary = 0 WHERE company_id = .....

o anche

UPDATE contacts
SET is_primary = IF(id=[USERID],1,0)
WHERE company_id = (
    SELECT company_id FROM contacts WHERE id = [USERID]
);

Basta mettere un'alternativa là fuori - personalmente avrei probabilmente guardare al approccio FK se invece di questo tipo di soluzione alternativa cioè avere un campo nella tabella società con un campo primary_user_id

.

Modifica Metodo w / o fare affidamento su un campo contact.is_primary

metodo alternativo, prima di tutto rimuovere is_primary dai contatti. In secondo luogo aggiungere un campo INT "primary_contact_id" in società. In terzo luogo, quando si cambia il contatto principale, basta cambiare che primary_contact_id impedendo così ogni possibilità che vi sia più di 1 contatto principale in qualsiasi momento e il tutto senza la necessità di trigger ecc sullo sfondo.

Questa opzione avrebbe funzionato bene in qualsiasi motore come è semplicemente aggiornando un campo INT, qualsiasi affidamento su FK del ecc potrebbe essere aggiunto / rimosso come richiesto, ma esso è la cosa più semplice è solo cambiando un valore campi INT

Questa opzione è valida a patto che avete bisogno di uno e precisamente un collegamento dalle aziende ai contatti flagging un primario

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top