Come evitare null in chiave primaria? [chiuso]

0

Ho bisogno di creare una tabella che sembra richiedere due colonne chiave primaria con una delle colonne nullable.

Ma secondo le domande che ho letto su Stack Overflow è indesiderabile e persino contro gli standard SQL (ad esempio: valore NULL nella chiave primaria a più colonne )

Tuttavia non riesco a capire come evitarlo, e apprezzerei l'aiuto. Ecco il problema:

Devo monitorare le prestazioni di vari blocchi che possono riempire lo spazio sulla pagina del sito di e-commerce, ma alcuni di questi blocchi hanno configurazioni multiple che devo tracciare separatamente e altri no.

Ho pensato di usare un PK a due colonne, una colonna sarebbe char(8) con il nome del blocco, l'altro sarebbe l'ID della configurazione che conterrebbe null per i blocchi che sono immutabili o l'ID della configurazione dal rispettivo tabella di configurazione del blocco (in pratica FK) per gli altri.

Come faccio a farlo senza una colonna nullable in PK?

(Ho già pensato di aggiungere la colonna config_id che sarebbe PK ma poi le stesse due colonne dovrebbero essere uniche e sembra non arrivare da nessuna parte.)

    
posta Lukáš Rutar 31.10.2015 - 21:10
fonte

4 risposte

3

Usa config id = 0 invece di NULL come indicatore per "blocchi immutabili" e assicurati che ogni record di configurazione abbia un ID > 0. Se si desidera utilizzare la colonna id come chiave esterna, creare un record di configurazione artificiale con id = 0 (che il programma interpreta come "nessuna configurazione").

Tecnicamente (e indipendentemente dal precedente suggerimento), potrebbe essere utile non utilizzare la chiave combinata a due colonne come chiave primaria direttamente, ma per introdurre una colonna aggiuntiva "blockId" per la chiave primaria. In effetti, quando progetto uno schema relazionale, di solito uso una colonna intera del modulo "NomeTabella" per ogni tabella come chiave primaria, il che semplifica molte cose.

Tieni presente che l'introduzione di una colonna blockId risolverà il tuo problema originale solo su alcuni database - alcuni sistemi db consentono valori NULL come parte di UNIQUE CONSTRAINT , altri non consentono questo e alcuni altri lo consentono, ma non garantiscono l'unicità per i record in cui una colonna contiene NULL. Potresti considerare di controllare di cosa è capace il tuo sistema DB, ma consiglio vivamente di usare il mio suggerimento iniziale per risolvere il tuo problema in maniera indipendente dal database.

    
risposta data 01.11.2015 - 00:11
fonte
1

Il tuo problema è una delle relazioni opzionali tra due siti. Alcuni blocchi hanno configurazioni multiple e altri no. Prendo questo per significare che i blocchi che non hanno più configurazioni non hanno alcuna configurazione. Se hanno una configurazione, il problema scompare.

Hai bisogno di tre tavoli. Uno per i blocchi, uno per le configurazioni e uno per le configurazioni dei blocchi. La terza tabella rappresenta la relazione e contiene due chiavi esterne. Il suo PK è la combinazione delle due chiavi esterne, prese insieme, se si desidera che la relazione sia molti-a-molti. In caso contrario, il PK può essere uno dei due campi.

Quando un determinato blocco non ha alcuna relazione con alcuna configurazione, basta omettere la riga nella terza tabella. Nessun problema! Non ci sono null qui, c'è solo una riga omessa!

Se vuoi saperne di più, guarda "Sesta forma normale".

    
risposta data 01.11.2015 - 12:50
fonte
0

Difficile da dire dalla tua domanda, ma di solito trovo che ogni tabella dovrebbe avere una sola chiave primaria.

Probabilmente hai bisogno di avere una terza colonna come chiave primaria per la tabella con le due colonne esistenti come FK

Quando crei una chiave primaria tra più FK, puoi scoprire che non diventa univoco man mano che il software si evolve, o per esempio la tua configurazione della pagina cambia nel tempo.

    
risposta data 01.11.2015 - 00:23
fonte
0

Vedo due potenziali problemi con il tuo progetto:

  1. Invertire un'associazione in bianco e nero e le relative configurazioni inserendo una chiave esterna nella parte sbagliata di tale associazione
  2. Disporre di due sottotipi di blocchi (immutabili e quelli con configurazioni) in un'unica tabella: "ereditarietà di una tabella"

Sembra che tu stia cercando di implementare un'associazione 1-to-N standard b / w blocks e block_configurations , ma per qualche motivo hai deciso di capovolgerla inserendo la chiave di configurazione in ogni blocco, mentre dovresti fare il contrario, cioè dovresti inserire block_id in block_configurations invece di mettere configuration_id in blocks :

CREATE TABLE blocks (
  block_id CHAR(10),
  is_immutable BIT(1) NOT NULL,
  PRIMARY KEY (block_id)
);

CREATE TABLE block_configurations (
  configuration_id INT(10) AUTO_INCREMENT,
  block_id CHAR(10) NOT NULL,
  PRIMARY KEY (configuration_id),
  FOREIGN KEY block_id_fk(block_id) REFERENCES blocks(block_id)
    ON UPDATE CASCADE
    ON DELETE RESTRICT
);

L'unica cosa che non viene applicata da questo schema è il fatto che i blocchi immutabili non devono avere record di configurazione associati. Puoi farlo usando i trigger, ma la soluzione migliore è usare tabelle configurable_blocks e immutable_blocks separate, poiché in questo caso ci sono due sottotipi di blocchi. Ci sono due modi per farlo: "ereditarietà di tabelle multiple" e "ereditarietà di tabelle di classi". Quello che ho mostrato sopra è una "ereditarietà di una tabella singola", in cui due sottotipi di blocchi sono memorizzati all'interno di una singola tabella.

Ecco un esempio con ereditarietà di più tabelle:

CREATE TABLE immutable_blocks (
  block_id CHAR(10),
  PRIMARY KEY (block_id)
);

CREATE TABLE configurable_blocks (
  block_id CHAR(10),
  PRIMARY KEY (block_id)
);

CREATE TABLE block_configurations (
  configuration_id INT(10) AUTO_INCREMENT,
  block_id CHAR(10) NOT NULL,
  PRIMARY KEY (configuration_id),
  FOREIGN KEY configurable_block_id_fk(block_id) 
    REFERENCES configurable_blocks(block_id)
    ON UPDATE CASCADE
    ON DELETE RESTRICT
);

Questo design ha un altro difetto: se si hanno attributi comuni in due sottotipi di blocchi, è necessario duplicarli su due tabelle. Ecco dove risiede l'ereditarietà delle tabelle delle classi:

CREATE TABLE blocks (
  block_id CHAR(10),
  description VARCHAR(100), -- common field
  PRIMARY KEY (block_id)
);

CREATE TABLE immutable_blocks (
  block_id CHAR(10),
  FOREIGN KEY block_id_fk(block_id) REFERENCES blocks(block_id)
    ON UPDATE CASCADE
    ON DELETE RESTRICT
);

CREATE TABLE configurable_blocks (
  block_id CHAR(10),
  FOREIGN KEY block_id_fk(block_id) REFERENCES blocks(block_id)
    ON UPDATE CASCADE
    ON DELETE RESTRICT
);

CREATE TABLE block_configurations (
  ... same here, still references only configurable_blocks ...
);

Questo design garantisce l'integrità referenziale e consente di separare i campi specifici comuni e sottotipo.

Lettura correlata:

  • Antipattern SQL , capitolo "Associazioni polimorfiche": le soluzioni in questo capitolo si applicano a questo caso
  • SQL Antipatterns, capitolo "Entity-Attribute-Value" - descrive l'ereditarietà di tabelle single / multiple / class, in relazione al problema di avere sottotipi di qualche entità
risposta data 01.11.2015 - 10:51
fonte

Leggi altre domande sui tag