MySQL – Relazione Uno A Uno?

Sto cercando di raggiungere la relazione uno A Uno in un database MySQL. Per esempio, diciamo che ho la tabella degli Utenti e dei Conti tabella. E voglio essere sicuro che c’è un Utente può avere un solo account. E che non ci può essere un solo Account per ogni utente.

Ho trovato due soluzioni per questo, ma non so cosa usare, e ci sono altre opzioni.

Prima soluzione:

DROP DATABASE IF EXISTS test;
CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci;
USE test;

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    user_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE accounts(
    id INT NOT NULL AUTO_INCREMENT,
    account_name VARCHAR(45) NOT NULL,
    user_id INT UNIQUE,
    PRIMARY KEY(id),
    FOREIGN KEY(user_id) REFERENCES users(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

In questo esempio, è possibile definire l’foreign key account che punta alla chiave primaria di utenti.
E allora faccio chiave esterna UNICA, quindi non può essere identica due utenti in conti.
Per unire tabelle vorrei utilizzare questa query:

SELECT * FROM users JOIN accounts ON users.id = accounts.user_id;

Seconda soluzione:

DROP DATABASE IF EXISTS test;
CREATE DATABASE test CHARSET = utf8 COLLATE = utf8_general_ci;
USE test;

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    user_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE accounts(
    id INT NOT NULL AUTO_INCREMENT,
    account_name VARCHAR(45) NOT NULL,
    PRIMARY KEY(id),
    FOREIGN KEY(id) REFERENCES users(id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

In questo esempio, creare una chiave esterna che punti dalla chiave primaria di una chiave primaria di un’altra tabella. Dal momento che le Chiavi Primarie sono UNICI per impostazione predefinita, questo la rende una relazione uno-a-Uno.
Per unire tabelle posso usare questo:

SELECT * FROM users JOIN accounts ON users.id = accounts.id;

Ora le domande:

  • Qual è il modo migliore per creare relazione uno a Uno in MySQL?
  • Ci sono altre soluzioni oltre a questi due?

Sto usando MySQL Workbench, e quando penso relazione uno A Uno in un diagramma REE e lasciare MySQL Workbench produrre codice SQL, ho Uno a Molti relazione :S Che è quello che mi confondi :S

E se provo a importare qualsiasi di queste soluzioni in MySQL Workbench diagramma EER, riconosce relazioni Uno-a-Molti :S Che è anche fonte di confusione.

Così, quale sarebbe il miglior modo per definire la relazione uno a Uno in MySQL DDL. E quali possibilità ci sono di ottenere questo?

  • Giusto per essere chiari, se stai facendo un rapporto di 1:1 in un database, si dovrebbe davvero essere se stessi chiedendo se non stai facendo il lavoro per voi stessi, senza una buona ragione. Ho molto raramente casi in cui non era meglio semplicemente di mettere tutti i valori in una singola tabella.
  • Lei ha parlato di “so che ci sono alcune risposte sulla Relazione uno A Uno”. Sarebbe bello se si collega a quelli che hai visto nel caso qualcun altro da internet trova la sua soluzione in una di quelle domande.
InformationsquelleAutor Limeni | 2012-11-30



3 Replies
  1. 42

    Dal momento che le Chiavi Primarie sono UNICI per impostazione predefinita, questo la rende una relazione uno-a-Uno.

    No, che rende la relazione “uno a zero o uno”. Che cosa hai veramente bisogno?

    Se , quindi la tua “seconda soluzione” è meglio:

    • è più semplice,
    • prende meno spazio di archiviazione1 (e, pertanto, cache “più grandi”)
    • hes meno gli indici di mantenere2, i cui benefici per la manipolazione dei dati,
    • e (dal momento che si sta utilizzando InnoDB) naturalmente cluster i dati, in modo che gli utenti che sono vicini, avranno il loro account archiviati assieme, che potrebbe beneficiare della cache di località e di alcuni tipi di scansioni di range.

    BTW, è necessario fare accounts.id un comune intero (non auto-increment) per questo lavoro.

    Se non, vedi sotto…

    Qual è il modo migliore per creare relazione uno a Uno in MySQL?

    Bene, “migliore” è un sovraccarico parola, ma “standard” soluzione sarebbe la stessa di qualsiasi altro database: mettere entrambe le entità (utente e account nel tuo caso) nella stessa tabella fisica.

    Ci sono altre soluzioni oltre a questi due?

    Teoricamente, si potrebbe fare circolare FKs tra le due PKs, ma che richiederebbe differite vincoli per risolvere il pollo-e-uovo problema, che, purtroppo, non sono supportati in MySQL.

    E se provo a importare qualsiasi di queste soluzioni in MySQL Workbench diagramma EER, riconosce relazioni Uno-a-Molti :S anche questo è fonte di confusione.

    Non ho molta esperienza pratica con quel particolare strumento per la modellazione, ma sto indovinando che è perché è “uno a molti”, dove lato “molti” è stata ridotta a 1 rendendolo unico. Si prega di ricordare che “molti” non significa “1 o molti”, significa “0 o molti”, in modo che il “capped” versione davvero significa “0 o 1”.


    1 Non solo nella conservazione di spesa per il campo, ma per l’indice secondario e. E dal momento che si sta utilizzando InnoDB che sempre cluster tavoli, attenzione che gli indici secondari sono anche più costosi in cluster di tavoli che sono in heap-based tabelle.

    2 InnoDB richiede indici su chiavi esterne.

    • Il mio piacere! BTW, questo è un sito in inglese, e utilizzando la (in questo caso il nostro) lingua locale non è raccomandato.
    • si dovrebbe avere poco spiegato come “chiave primaria” approccio implica la soluzione di uno (zero o uno). Mi ci sono voluti seconda revisione per ottenere l’idea che c’è dietro! Tuttavia, è stata informativo
  2. 9

    Il tuo primo approccio genera due chiavi candidate nella tabella conti: id e user_id.

    Suggerisco perciò il secondo approccio, vale a dire utilizzando la chiave esterna la chiave primaria. Questo:

    • utilizza una colonna di minore
    • consente di identificare in modo univoco ogni riga
    • permette di far corrispondere account utente
    • Grazie! Sapete perché MySQL Workbench diagramma EER vede questa relazione uno -> molti? :S
    • Trovato la soluzione per MySQL Workbench: bugs.mysql.com/bug.php?id=43920 roba Interessante, non è un bug, dopo tutto…
    • Penso che si potrebbe ottenere nei guai utilizzando gli Id come chiave esterna. Non è possibile garantire che entrambi gli Id sono identici, perché il database di auto-genera in loro (in teoria che dovrebbe è sempre la stessa, ma non si può assumere). Infatti, dal momento che il tuo esempio non hanno NOT NULL definito per l’account->rapporto utente, immagino che sia possibile avere un account senza che l’utente o il contrario? Se avete mai avuto una situazione in cui si creato più utenti, quindi creato il loro account in un ordine diverso, il vostro rapporto si sarebbe rotto.
    • Proprio come volevo chiedere prossima 🙂 presumo che il modo migliore per andare con Una che utilizza MySQL potrebbe essere l’utilizzo di chiave esterna e l’aggiunta di unico vincolare, come in 1. esempio
    • Penso che la soluzione di pulitura. Pragmaticamente parlando, se avete sempre creare ed eliminare entrambe le tabelle contemporaneamente, utilizzando l’Id è probabilmente andando mai effettivamente causare un problema, ma se mai colpito un bordo nel caso in cui l’Id in qualche modo ha ottenuto fuori sincrono, si potrebbe trovare te stesso in un mondo di dolore.
    • perchè vuoi auto-generare una chiave esterna?
    • Purtroppo, interruzioni di corrente, guasti hardware e i bug sono un fatto della vita. Auto-incremento non è transazionale, in modo che se uno qualsiasi di questi problemi succede tra il primo e il secondo INSERTO, sarà spingere l’incremento automatico di whack, anche se l’operazione stessa viene eseguito il rollback.

  3. -2

    Che cosa circa il seguente approccio

    1. Creare la Tabella utente

      CREATE TABLE `user` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `name` varchar(45) DEFAULT NULL,
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    2. Creare la Tabella account con un indice univoco di user_id e account_id con una chiave esterna relazione utente/account e una chiave primaria su user_id and account_id

      CREATE TABLE `account` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `name` varchar(45) DEFAULT NULL,
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    3. Creare la Tabella user2account

      CREATE TABLE `user2account` (
        `user_id` int(11) NOT NULL,
        `account_id` int(11) NOT NULL,
        PRIMARY KEY (`user_id`,`account_id`),
        UNIQUE KEY `FK_account_idx` (`account_id`),
        UNIQUE KEY `FK_user_idx` (`user_id`),
        CONSTRAINT `FK_account` FOREIGN KEY (`account_id`) REFERENCES         `account` (`id`),
        CONSTRAINT `FK_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    Mentre questa soluzione è la più grande impronta nel database, ci sono alcuni vantaggi.

    • Mettere il FK_Key nella tabella utente o l’account tabella è qualcosa che mi aspetto da uno a molti releation (utente ha molti conti …)
    • Mentre questo user2account approccio è principalmente utilizzato per definire le relazioni molti a molti, l’aggiunta di un vincolo UNIVOCO user_id e account_id consentirà di evitare la creazione di qualcosa di più che una relazione uno a uno.

    Il vantaggio principale vedo in questa soluzione è che si può dividere il lavoro in codice diversi livelli o i dipartimenti, in una società

    • Dipartimento è responsabile per la creazione di utenti, questo è possibile anche senza i permessi di scrittura alla tabella conti
    • B dipartimento è responsabile per la creazione di un account, questo è possibile anche senza i permessi di scrittura per l’utente tabella
    • Dipartimento C è responsabile per la creazione di mappatura, questo è possibile anche senza i permessi di scrittura all’utente o account tabella
    • Una volta Departement C ha creato una mappatura né l’utente né il conto può essere eliminato dal dipartimento di A o di B, senza chiedere il dipartimento C per eliminare il mapping prima.

Lascia un commento