2011-12-30 18 views
5

Considerando un errore 1NF, nessun gruppo di elementi ripetuto, cosa succederebbe se si volesse avere un limite impostato sul numero di un gruppo ripetuto?Si tratta di un errore 1NF?

Ad esempio, si desidera che uno studente abbia solo 3 numeri di telefono elencati. Non piu. Avere una tabella come segue può essere considerata un errore 1NF?

Student 1 Phone1 Phone2 Phone3 
Sally  111-1111 222-2222 333-3333 
John   555-5555 999-9999 NULL 

Si creerebbe un limite. Questa progettazione di database è accettabile ed efficiente?

Sarebbe meglio mettere i numeri di telefono in una tabella separata, come richiedono gli errori 1NF? Come creeresti il ​​limite di 3 numeri per utente se fosse in una tabella separata?

+1

C'è un ottimo write-up @ http://en.wikipedia.org/wiki/First_normal_form#Repeating_groups –

risposta

6

No, non è normalizzato. Avrai sprecato spazio nella tua tabella quando ci sono valori nulli, e se vuoi fare cose come cercare un particolare numero di telefono, dovrai cercare tutte e tre le colonne. Utilizzare invece una tabella separata (StudentPhoneNumbers, ad esempio) che li memorizza. Se si desidera limitare a tre, utilizzare un trigger per prevenire più di tre per studente.

+2

Non in 2NF o 3NF, ma è ** ** in 1NF, che è ciò che il OP sta chiedendo informazioni. – Oded

+0

Il server SQL supporta i trigger? \ – user

+1

@ user1122200 - Perché stai chiedendo di SQL Server? Hai taggato MySQL? –

6

1NF vieta di ripetere gli elenchi di seguito. Il vostro disegno viola questa, e così sarebbe il seguente disegno:

Student  Phones 
'John D' '555-5555, 666-6666, 777-7777' 
'Sally S' '111-1111, 222-2222' 

Il seguente disegno sarebbe viola 2NF, perché l'unica chiave primaria è Name, Phone, ma l'attributo Address non dipende dal Phone:

Name  Phone  Address 
'John D' '555-5555' '1 Square Village' 
'John D' '666-6666' '1 Square Village' 
'John D' '777-7777' '1 Square Village' 
'Sally S' '111-1111' '999 Flash City' 
'Sally S' '222-2222' '999 Flash City' 

Il design prossima violerebbe 3NF, perché AreaName non dipende dal nome, ma solo su Area:

Name  Area Phone AreaName 
'John D' '555' '5555' '111name' 
'John D' '666' '6666' '666name' 
'John D' '777' '7777' '777name' 
'Sally S' '111' '1111' '111name' 
'Sally S' '222' '2222' '222name' 

Anche se il tuo design viola 1NF, è una scelta eccellente. La complessità dell'aggiunta di una tabella PhoneNumber non è quasi mai giustificata.

Pensa a quanto diventa difficile un aggiornamento per un cliente se sei conforme a 1NF. I numeri sarebbero in una tabella separata. Quindi, se qualcuno invia un modulo con un elenco aggiornato di numeri di telefono, come cambieresti il ​​database? Prima dovresti recuperare l'elenco esistente di numeri. Quindi dovresti confrontarli con l'elenco inviato. Quindi dovresti eliminare o inserire righe in base alla differenza. Un diavolo di una soluzione complessa.

Se ci si attiene alla soluzione, è sufficiente aggiornare le tre colonne. Il tempo risparmiato può essere speso per le funzionalità reali! O anche scrivendo lunghe risposte su Stack Overflow.

+0

lol. Sembra quindi che un errore 1NF possa verificarsi anche se esiste un limite al numero di gruppi ripetuti, non solo per i gruppi ripetuti per cui non esiste un limite impostato. – user

+1

In realtà, dovresti semplicemente eliminare tutti i suoi numeri di telefono e quindi inserire tutti i dati dal modulo - oppure potresti semplicemente creare un modulo separato (ajax lo rende così bello) in cui puoi eliminare singoli numeri di telefono e aggiungerne di nuovi. Quindi, tutto sommato, dipende in gran parte dalla vostra applicazione cosa è più comodo. Naturalmente, a meno che non si utilizzi un ORM in cui la tabella separata con le relazioni appropriate possa fornire un array per i numeri di telefono dell'utente. – ThiefMaster

+0

corretto. Le forme normali provengono da "Algebra relazionale", per una buona introduzione vedi la [classe libera di Stanford] (http://www.db-class.org/). Direi che la forma normale è un ottimo strumento, ma devi valutare i costi e i benefici e non applicarla alla cieca. – Andomar

1

user1122200, supponiamo che la progettazione del database cresca. E devi assegnare determinati dati a ciascun numero di telefono (come la posizione del telefono: "casa", "lavoro", ...). In questo caso desidererai un tavolo del telefono. Inoltre, supose che è necessario trovare gli studenti di numero di telefono (come i servizi di Pizza Hut o taxi quando qualcuno chiama), è più facile una query in un design ben normalizzato che questa query:

select * 
from students 
where 
    Phone1 = '91112223' or 
    Phone2 = '91112223' or 
    Phone3 = '91112223' 
3

La variabile relazione (relvar) effettivamente viola 1NF ma forse non per il motivo che ci si aspetta: è la presenza del null che viola 1NF. Se pensi che il tuo relvar contenga un gruppo ripetuto, ripensaci.

La prima forma normale, o semplicemente "normalizzata", è il requisito minimo per il modello relazionale.Per citare Chris Data:

per definizione, null non è un valore. Ne consegue che: un "tipo" che contiene un null non è un tipo (perché i tipi contengono valori); Una "tupla" che contiene un null non è una tupla (poiché le tuple contengono valori); Una "relazione" non contiene una relazione (poiché le relazioni contengono tuple e le tuple non contengono valori null). In effetti, i valori nulli violano il principio relazionale più fondamentale di tutto-viz., Il principio delle informazioni . La rete di tutto questo è che se i valori nulli sono presenti, allora non stiamo certamente parlando del modello relazionale (non so di cosa stiamo parlando, ma non è il modello relazionale ); l'intero edificio si sbriciola e tutte le scommesse sono andate via.

Il punto relativo alla ripetizione di gruppi e 1NF è complicato da spiegare e non ci proverò. Invece, ti invito a leggere Facts and Fallacies about First Normal Form, in particolare la sezione "L'ambiguità di gruppi ripetuti".

Supponendo che il valore nullo sia stato eliminato, il relvar avrebbe soddisfatto 1NF ma si noti che avremmo bisogno di ulteriori informazioni (ad esempio chiavi) per determinare se soddisferebbe anche le forme normali più elevate.

+0

Questa relazione contiene un gruppo ripetuto, il gruppo Numero di telefono. In parole povere, ciò è chiaramente osservabile dalla relazione di cui sopra. La presenza del valore NULL lo rende una violazione 1NF ancora di più. L'obiettivo principale qui è la creazione di un gruppo di elementi in cui si desidera un numero limitato. – user

+1

@user: vedo tre attributi distinti denominati rispettivamente 'Phone1',' Phone2' e 'Phone3'; potevano essere chiamati 'home_phone',' mobile_phone' e 'work_phone', i nomi non sono significativi, idem i loro tipi. Non vedo "Numero di telefono". – onedaywhen

+0

In un modello di dati logici, se i tipi di dati nelle colonne in un'entità sono simili, sono per definizione un gruppo ripetuto. Lo stesso vale per Hobby1, Hobby2, Hobby3 o Sport1, Sport2, Sport3. – user

1

Come creeresti il ​​limite di 3 numeri per utente se fosse in una tabella separata?

Suppongo che uno studente possa avere zero, uno due o tre numeri di telefono.

Se il prodotto SQL supportato completa SQL-92:

CREATE TABLE Students 
(
student_name VARCHAR(20) NOT NULL UNIQUE 
); 

CREATE TABLE StudentPhonebook 
(
student_name VARCHAR(20) NOT NULL 
    REFERENCES Students (student_name), 
phone_number CHAR(8) NOT NULL 
    CHECK (phone_number LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), 
UNIQUE (student_name, phone_number) 
); 

CREATE ASSERTION students_max_three_phone_numbers 
    CHECK (
      NOT EXISTS (
         SELECT * 
         FROM (
           SELECT student_name, COUNT(*) AS tally 
           FROM StudentPhonebook 
           GROUP 
            BY student_name 
          ) AS DT1 
         WHERE tally > 3 
        ) 
     ); 

MySql non supporta CHECK di qualsiasi sapore e nessun prodotto SQL supporta CREATE ASSERTION vincoli in modo che il di cui sopra devono presumibilmente essere scritte usando codice procedurale per esempio trigger.

Fuori di interesse, se il prodotto SQL supportato a livello di riga CHECK vincoli (come fanno molti), si può usare un attributo occurrence con un vincolo BETWEEN 1 AND 3 quindi includere questo attributo in un vincolo di chiave ad esempio

CREATE TABLE StudentPhonebook 
(
student_name VARCHAR(20) NOT NULL 
    REFERENCES Students (student_name), 
phone_number CHAR(8) NOT NULL 
    CHECK (phone_number LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), 
occurrence INTEGER DEFAULT 1 NOT NULL 
    CHECK (occurrence BETWEEN 1 AND 3), 
UNIQUE (student_name, phone_number), 
UNIQUE (student_name, occurrence) 
); 
+1

In MySQL, il vincolo 'CHECK (occorrenza tra 1 e 3) 'può essere simulato con un' FOREIGN KEY' in una tabella di riferimento con esattamente 3 righe. –

Problemi correlati