Credo che il titolo sia autoesplicativo. Come crei la struttura della tabella in PostgreSQL per creare una relazione molti-a-molti.
Il mio esempio:
Product(name, price);
Bill(name, date, Products);
Credo che il titolo sia autoesplicativo. Come crei la struttura della tabella in PostgreSQL per creare una relazione molti-a-molti.
Il mio esempio:
Product(name, price);
Bill(name, date, Products);
Risposte:
Le istruzioni SQL DDL (linguaggio di definizione dei dati) potrebbero avere questo aspetto:
CREATE TABLE product (
product_id serial PRIMARY KEY -- implicit primary key constraint
, product text NOT NULL
, price numeric NOT NULL DEFAULT 0
);
CREATE TABLE bill (
bill_id serial PRIMARY KEY
, bill text NOT NULL
, billdate date NOT NULL DEFAULT CURRENT_DATE
);
CREATE TABLE bill_product (
bill_id int REFERENCES bill (bill_id) ON UPDATE CASCADE ON DELETE CASCADE
, product_id int REFERENCES product (product_id) ON UPDATE CASCADE
, amount numeric NOT NULL DEFAULT 1
, CONSTRAINT bill_product_pkey PRIMARY KEY (bill_id, product_id) -- explicit pk
);
Ho apportato alcune modifiche:
La relazione n: m è normalmente implementata da una tabella separata, bill_product
in questo caso.
Ho aggiunto serial
colonne come chiavi primarie surrogate . In Postgres 10 o versioni successive, considera invece una IDENTITY
colonna . Vedere:
Lo consiglio vivamente, perché il nome di un prodotto è difficilmente univoco (non è una buona "chiave naturale"). Inoltre, l'applicazione dell'unicità e il riferimento alla colonna nelle chiavi esterne è in genere più conveniente con un 4 byte integer
(o anche un 8 byte bigint
) rispetto a una stringa archiviata come text
o varchar
.
Non utilizzare nomi di tipi di dati di base date
come identificatori . Sebbene ciò sia possibile, è di cattivo stile e porta a errori e messaggi di errore confusi. Utilizza identificatori legali, minuscoli e non quotati . Non usare mai parole riservate ed evita gli identificatori di maiuscole e minuscole tra virgolette doppie, se puoi.
"nome" non è un buon nome. Ho rinominato la colonna della tabella product
in product
(o product_name
o simile). Questa è una convenzione di denominazione migliore . Altrimenti, quando unisci un paio di tabelle in una query, cosa che fai molto in un database relazionale, ti ritroverai con più colonne chiamate "nome" e dovrai usare gli alias di colonna per risolvere il pasticcio. Non è d'aiuto. Un altro anti-pattern molto diffuso sarebbe semplicemente "id" come nome della colonna.
Non sono sicuro di quale bill
sarebbe il nome di a . bill_id
probabilmente sarà sufficiente in questo caso.
price
è del tipo di datinumeric
per memorizzare i numeri frazionari esattamente come inseriti (tipo di precisione arbitraria invece del tipo a virgola mobile). Se ti occupi esclusivamente di numeri interi, fallo integer
. Ad esempio, puoi salvare i prezzi in centesimi .
Il amount
( "Products"
nella tua domanda) va nella tabella di collegamento bill_product
ed è anch'esso di tipo numeric
. Di nuovo, integer
se ti occupi esclusivamente di numeri interi.
Vedete le chiavi esterne in bill_product
? Ho creato sia per le modifiche a cascata: ON UPDATE CASCADE
. Se un product_id
o bill_id
dovesse cambiare, la modifica viene applicata a cascata a tutte le voci dipendenti in bill_product
e nulla si interrompe. Questi sono solo riferimenti senza significato proprio.
Ho anche usato ON DELETE CASCADE
per bill_id
: Se una fattura viene cancellata, i suoi dettagli muoiono con essa.
Non è così per i prodotti: non si desidera eliminare un prodotto utilizzato in una fattura. Postgres genererà un errore se ci provi. Aggiungerebbe un'altra colonna a product
per contrassegnare le righe obsolete ("eliminazione temporanea").
Tutte le colonne in questo esempio di base finiscono per essere NOT NULL
, quindi i NULL
valori non sono consentiti. (Sì, tutte le colonne: le colonne della chiave primaria vengono definite UNIQUE NOT NULL
automaticamente.) Questo perché i NULL
valori non avrebbero senso in nessuna delle colonne. Rende più facile la vita di un principiante. Ma non sarà possibile ottenere via così facilmente, è necessario capire NULL
la gestione in ogni caso. Colonne aggiuntive potrebbero consentire NULL
valori, funzioni e join possono introdurre NULL
valori nelle query, ecc.
Leggere il capitolo sul CREATE TABLE
manuale .
Le chiavi primarie sono implementate con un indice univoco sulle colonne chiave, che rende veloci le query con le condizioni sulle colonne PK. Tuttavia, la sequenza delle colonne chiave è rilevante nelle chiavi a più colonne. Poiché il PK on bill_product
è attivo (bill_id, product_id)
nel mio esempio, potresti voler aggiungere un altro indice su just product_id
o (product_id, bill_id)
se hai query alla ricerca di un dato product_id
e no bill_id
. Vedere:
Leggere il capitolo sugli indici nel manuale .
bill_product
? Normalmente dovrebbe assomiglia: CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
. È giusto?
bill
. Abbiamo bisogno della quantità per articolo aggiunto in bill_product
.