Esiste un valido motivo per cui le colonne in SQL sono annullabili per impostazione predefinita?

8

Come studente di CS, ho imparato un numero decente di linguaggi di programmazione nel corso degli anni, molti dei quali hanno avuto un concetto di tipo "nullable" o "opzionale". Nota che io sono non che parla di puntatori o riferimenti null, o di linguaggi debolmente tipizzati come JavaScript, dove tutto può essere null . Esempi di ciò di cui sto parlando includono boost::optional (C ++), java.util.Optional (Java 8.0), prelude.Maybe (Haskell) e tutti i '?' tipi (ad esempio int? , float? , C # e Kotlin). Si tratta di costrutti che aggiungono il nullability a un tipo precedentemente non annullabile all'interno di un sistema di tipi statici e rigorosi.

SQL ha un concetto simile: un tipo come INTEGER può essere reso nullable o non annullabile, ma c'è una svolta. In SQL, INTEGER è annullabile per impostazione predefinita e deve essere scritto in modo esplicito come INTEGER NOT NULL per non essere annullabile.

Mi sembra estremamente contro-intuitivo e potenzialmente pericoloso per consentire a NULL di essere il comportamento predefinito. Ovviamente SQL è stato intorno così a lungo a questo punto che (la maggior parte) gli sviluppatori SQL hanno sviluppato una sana consapevolezza delle insidie di NULL. Ma non posso fare a meno di immaginare che nei primi giorni NULL spesso si insinuava in luoghi inaspettati e problematici.

SQL precede tutti gli esempi che ho fornito, quindi è possibile che questa sia semplicemente una questione di evoluzione storica. Tuttavia, devo chiedere, c'è qualche buona ragione per il linguaggio che deve essere progettato in questo modo, con tipi che sono annullabili per impostazione predefinita?

Se è così, è solo una ragione storica, o la logica resiste al design del database oggi?

Modifica: non sto chiedendo perché NULL è una parte di SQL o perché le colonne nullable sono utili. Sto solo chiedendo perché la colonna sia annullabile di default . Ad esempio, perché scriviamo:

column1 FLOAT,
column2 FLOAT NOT NULL

Piuttosto che:

column1 FLOAT NULLABLE,
column2 FLOAT
    
posta ApproachingDarknessFish 08.11.2017 - 04:47
fonte

8 risposte

23

All'università mi è stato insegnato che è vero il contrario. È molto più pericoloso creare qualcosa not null senza motivo. Con un campo nullable, la cosa peggiore che può capitare è di inciampare nell'applicazione che accede ai dati. Oh caro, torna indietro e correggi l'app ...

Con un campo non nullo non è possibile aggiungere record perché alcuni campi arbitrari non sono disponibili. Ora devi modificare il modello di dati e potenzialmente correggere il risultato in MOLTI luoghi diversi ...

È bene pensare a null come "sconosciuto". Se esiste una ragione plausibile per cui potresti voler inserire un record senza sapere qualcosa, allora dovrebbe essere annullabile.

Uno dei miei docenti universitari lo ha descritto in questo modo:

Apocryphally I've heard of a sales system in the USA which required customer's social security number to make a sale. All the till operators did when a foreigner came to the till was enter 000-00-0000. But then others would enter 123-45-6789. This makes it impossible to identify junk. It's much better to allow a field to be blank than to force it to contain junk.

Or another story. I have genuinely been refused car insurance because I don't have two phone numbers. They absolutely would not give me insurance unless I gave them two. The sales guy suggested I just give a false one. In the end I refused to lie to an insurer and just went with another company.

In pratica riserva not null per i campi che sono necessari per dare un senso al record. Ad esempio:

Una tabella di posti con campi (ID, Nome del luogo, Paese, Longitudine, Latitudine) ... "longitudine" "latitudine" dovrebbe essere nullable in modo da poter memorizzare l'esistenza di un luogo prima di sapere dove si trova.

Ma se hai un tavolo il cui unico scopo è quello di conservare i coodati geografici con i campi (Item_id, longitudine, latitudine) l'intero record non ha senso se longitudine e latitudine sono nulle. Pertanto in questo caso dovrebbero essere not-null

Nella mia esperienza professionale sin dall'università, ci sono molti più campi che possono essere facoltativi di quelli che devono essere obbligatori.

    
risposta data 08.11.2017 - 05:51
fonte
8

It strikes me as extremely counter-intuitive...

Intuitivo è negli occhi di chi guarda e la tua opinione su ciò è modellata dalle cose a cui sei stato esposto. Vengo da un periodo in cui quel tipo di sicurezza non era standard e gli strumenti non facevano notare quando ti inventavi. Ho usato la sega a catena senza una protezione della lama abbastanza a lungo che il mio primo istinto è quello di evitare completamente l'intuizione, tornare al DDL e scoprire esattamente quali ipotesi lo schema mi consentirà di fare sui suoi dati.

...and potentially dangerous for allowing NULL's to be the default behavior.

Penso che stai esagerando con i pericoli relativi. NOT NULL ha il suo insieme di insidie che possono portare a bug ugualmente insidiosi. (Enumerarli sarebbe foraggio per una domanda diversa.)

Il designer di una tabella ha sempre l'opzione di vincolare una colonna NULL o NOT NULL e farà l'una o l'altra per aggirare il default, qualunque esso sia. Non vincolare correttamente una colonna è l'incapacità dello sviluppatore di seguire le regole aziendali. Non fare la cosa giusta altrove, basandosi sulla definizione della colonna, significa che uno sviluppatore non comprende i dati che gli vengono consegnati. Non ci sono soluzioni tecniche per entrambi.

Still, I have to ask, is there any good reason for the language to be designed this way, with types being nullable by default?

No, non c'è. Poiché entrambi hanno dei rischi, non c'è nemmeno una buona ragione per cui la lingua debba essere progettata nell'altro modo. Si riduce a raccogliere il tuo veleno.

    
risposta data 08.11.2017 - 14:56
fonte
6

Le colonne Nullable sono necessarie in SQL a causa di join esterni (noti anche come join di sinistra o giusti giusti). Quando la riga su un lato del join non ha corrispondenza sull'altro lato, i campi dell'altro lato devono avere NULL. Poiché l'output di un join può avere colonne nullable, anche le tabelle di base dovrebbero supportarle a causa del principio di chiusura relazionale (che in pratica indica che il risultato di una query o di una vista dovrebbe essere indistinguibile da una tabella di base).

Dato questo, SQL deve supportare colonne nullable. D'altra parte, le colonne non annullabili sono una funzione secondaria - SQL potrebbe funzionare anche senza di esse.

    
risposta data 08.11.2017 - 18:48
fonte
4

Giriamola e dì che hai ragione. Supponiamo che il tuo numero intero non sia nullo per impostazione predefinita.

Il che significa che deve avere un valore per impostazione predefinita. Anche quando non è noto.

Quindi quando aggiorni la tabella delle persone e hai due opzioni: È impossibile aggiornare la tabella perché non hai inserito il peso. O quando non hai fornito l'argomento del peso messo nello standard "-1 chili" quando sconosciuto.

Entrambe le situazioni sono indesiderabili. Vuoi essere in grado di aggiungere clienti, anche se non conosci il loro peso. Ma anche, non vuoi avere valori "proxy". I valori che sono segnaposto ma possono avere un significato reale, ad esempio: possono essere utilizzati in funzioni matematiche come "media" ma non sono valori reali.

Intendo quando si calcola un peso medio, -1 è un valore valido nella funzione media matematica, ma non come peso di una persona. Tu usi null e ora la tua funzione media sa di ignorare quel valore.

Inoltre, non vorrei davvero confrontare l'SQL con i linguaggi di programmazione quando discuto di null, sono intrinsecamente diversi, null in SQL è parte della teoria della progettazione di database relazionali.

    
risposta data 08.11.2017 - 11:47
fonte
2

No. Non vi è alcun motivo valido per cui SQL abbia come valore predefinito nullable. Infatti, molti importanti ricercatori nella teoria dei database relazionali non sono d'accordo con questa decisione di progettazione, forse in particolare Data di Chris , un frequente collaboratore con il designer originale del database relazionale, Edgar Codd . Date (insieme al coautore Hugh Darwen) ha pubblicato un noto libro sulla teoria relazionale (" The Third Manifesto ") che descrive i principi per le alternative progetta per una famiglia di linguaggi relazionali che chiamano "D", insieme ad un esempio di tale linguaggio chiamato "Tutorial D".

Le lingue D sono esplicitamente proibite dal supporto dei valori NULL ("D non includerà il concetto di una" relazione "in cui alcune" tuple "includono alcuni" attributi "che non hanno un valore."). Al contrario, i valori facoltativi sono supportati dall'avere tipi di dati alternativi che includono valori "non presenti" o valori simili nel segnaposto. I linguaggi D forniscono un modello avanzato per i tipi definiti dall'utente che consentirebbero l'estensione di qualsiasi tipo nativo con tali valori aggiuntivi.

Ci sono validi motivi teorici per cui questa è una buona idea, e Date & Darwen ha scritto molto su questo, così come sulle altre decisioni prese nel loro design. Consiglio vivamente di leggere il loro lavoro su questo argomento.

    
risposta data 08.11.2017 - 12:21
fonte
1

Non sono in disaccordo con la tua premessa su quale dovrebbe essere l'impostazione predefinita, ma è una buona pratica non assumere nulla come sviluppatore. Controllare le specifiche su una tabella di database non dovrebbe essere troppo difficile.

Più di una prospettiva DBA in cui ti verrà chiesto di caricare i dati in massa, in particolare quando si uniscono da altri sistemi, è meglio conoscere l'impostazione per ogni campo se si dispone di dati da inserire o meno.

Le aziende e le applicazioni sono gestite da persone. Se non sono programmatori, la definizione di "mai" e "sempre" non è esattamente la stessa e cambierà nel tempo. L'attuale impostazione nulla su un dato campo non dovrebbe essere sfocata.

    
risposta data 08.11.2017 - 15:50
fonte
0

I database sono animali diversi dai normali linguaggi di programmazione.

Poiché lo schema di una tabella è impostato, tutti i dati devono essere presenti quando si salvano le informazioni su una riga. Tuttavia, molti di questi dati potrebbero non essere necessari per creare una rappresentazione valida di un oggetto modello una volta caricati nel codice. Richiedere che tutti i dati debbano essere non nulli e popolati significherà che questi campi non obbligatori dovranno contenere un valore e tuttavia non ne hanno ancora uno, sono "sconosciuti".

Immagina di dover riempire TUTTI i campi sui moduli web TUTTO il tempo dato che non possono essere nulli nel database devono ricevere un valore ... una ricetta per la follia che è!

È possibile impostare alcuni valori riservati per rappresentare l'assenza di dati, una stringa vuota, un numero specifico, una data specifica ecc. a seconda del tipo di dati, ma quale valore scegliere? Quindi è necessario assicurarsi che tutti siano d'accordo sul fatto che questi valori arbitrari in realtà significano "sconosciuto" e non "1 ° gennaio 1970" per esempio. L'avversione nullo può richiedere molti moduli e ti porta lungo deviazioni contorte solo perché qualcuno ha detto che i valori nulli erano cattivi. Quanto sei preparato per essere pronto ad evitare di occuparti di null?

Avendo un unico valore universale per tutto ciò che è sconosciuto trovo molto preferibile rispetto all'utilizzo di alcuni set di valori costanti arbitrari. Non sto dicendo che i valori costanti sono cattivi e null è migliore, se il tuo modello è ben servito da una costante per rappresentare queste informazioni, allora lo usi con tutti i mezzi, ma ci sono molte situazioni in cui un null è proprio quello che si adatta meglio. Per tutti gli odiatori nulli, questa è una situazione in cui è stato negato nulla che avrebbe dovuto essere inventato!

Visto quanto sia pervasivo il concetto di "sconosciuto" in un database allora sì, direi che rendere i valori nullable un default ha molto senso.

Andando più a fondo e guardando altre risposte qui non sarei sorpreso di apprendere che i null non sono solo una "caratteristica del linguaggio" ma una parte integrante della teoria sottostante su cui si basa SQL. Si può rimuovere C (la velocità della luce) dalla relatività, ma il concetto di velocità massima assoluta rimane e deve ancora essere espresso in modo tale che possa tornare in qualche forma o forma.

    
risposta data 08.11.2017 - 23:54
fonte
0

Risposta breve: retrocompatibilità.

Risposta lunga:

In un database completamente normalizzato, NULL non è consentito in nessuna colonna. Ad esempio, supponiamo che ci sia una tabella chiamata MailingAddress che ha una colonna PostOfficeBox, che è un intero. Dal momento che non tutti hanno una casella postale, ci sono due modi per implementarlo.

Innanzitutto, potrebbe essere consentito NULL nella colonna.

In secondo luogo, PostOfficeBox viene rimosso da MailingAddress e una nuova tabella, PostOfficeBox viene creato con un numero di colonna e il suo PK è l'FK a MailingAddress. Ma ora sono necessarie due query per ottenere indirizzi di posta: uno per quelli senza caselle postali e uno per quelli con.

SQL consente NULL in colonne per scopi pratici.

    
risposta data 12.11.2017 - 14:29
fonte

Leggi altre domande sui tag