Domanda

Supponiamo che tu abbia una tabella per le filiali nella tua organizzazione. Alcuni di essi sono "principali". filiali e altri sono uffici satellite che si arrotolano in una filiale principale. A parte questa distinzione, che influisce solo su alcune cose nel sistema, i rami sono tutti peer e hanno gli stessi attributi (indirizzo, ecc.). Un modo per modellarlo è in una tabella come:

CREATE TABLE Branch (
    branch_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    branch_name VARCHAR(80) NOT NULL,
    street VARCHAR(80) NULL,
    city VARCHAR(30) NULL,
    state CHAR(2) NULL,
    zip CHAR(5) NULL,
    is_satellite_office BIT NOT NULL DEFAULT(0),
    satellite_to_branch_id INT NULL REFERENCES Branch(branch_id)
)

Dove is_satellite_office = 1 iff questo record è un satellite per un'altra filiale e satellite_to_branch_id si riferisce a quale filiale sei un satellite, se presente.

È abbastanza facile mettere un vincolo sulla tabella in modo che quelle due colonne concordino su un dato record:

CONSTRAINT [CK_Branch] CHECK 
  (
    (is_satellite_office = 0 AND satellite_to_branch_id IS NULL) 
    OR (is_satellite_office = 1 AND satellite_to_branch_id IS NOT NULL)
  )

Tuttavia, ciò che voglio davvero è un modo per garantire che questa ricorsione vada solo un livello in profondità ... cioè, se indico un ramo come mio genitore, non deve avere un genitore stesso e il suo valore per is_satellite_office deve essere 0. In altre parole, non voglio davvero una struttura ad albero completamente ricorsiva, voglio solo limitarla a una singola relazione padre / figlio. È così che scriverò il codice, e se c'è un modo per imporlo nel database che non funzionerà come una merda totale, mi piacerebbe.

Qualche idea? Sto lavorando su MSSQL 2005, ma sono preferite soluzioni generali (non specifiche del fornitore). E non è necessario applicare trigger, a meno che non ci sia davvero un altro modo per farlo.

EDIT: per essere chiari, satellite_to_branch_id è il puntatore ricorsivo a un altro record nella stessa tabella Branch. So che potrei rimuovere il is_satellite_office BIT e fare affidamento su IsNull (satellite_to_branch_id) per darmi le stesse informazioni, ma trovo che sia un po 'più chiaro per essere esplicito, e inoltre quale, questo non è l'essenza della domanda. Sto davvero cercando un modo puro di vincolo SQL per prevenire una profondità di ricorsione maggiore di 1.

È stato utile?

Soluzione

È possibile associare un vincolo di controllo al valore restituito di un UDF. Creare un UDF che accetta le colonne coinvolte come parametri di input, quindi controllare lo stato desiderato utilizzando una selezione nell'UDF.

Altri suggerimenti

Mi sembra un vincolo aziendale, difficile da applicare a livello di definizione dei dati. Non credo che l'algebra relazionale abbia alcun supporto per determinare un limite per la profondità dei riferimenti personali.

Non sei autorizzato a fare riferimento a una procedura memorizzata nel tuo vincolo? Puoi farlo in PostgreSQL, quindi sarei sorpreso se il 2005 non lo consentisse.

Che dire di questa struttura leggermente diversa?

CREATE TABLE Branch (
    branch_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    branch_name VARCHAR(80) NOT NULL,
    street VARCHAR(80) NULL,
    city VARCHAR(30) NULL,
    state CHAR(2) NULL,
    zip CHAR(5) NULL,
    parent_id int NULL
)

PARENT_ID punterà semplicemente al BRANCH_ID di un altro record nella stessa tabella. Se è nullo, allora sai che non ha genitori.

Quindi, per ottenere un livello di ricorsione, puoi semplicemente unire il tavolo a se stesso una volta, in questo modo:

SELECT
  PARENT.BRANCH_NAME AS PARENT_BRANCH
 ,CHILD.BRANCH_NAME AS CHILD_BRANCH
FROM
  BRANCH PARENT
 ,BRANCH CHILD
WHERE CHILD.PARENT_ID PARENT.BRANCH_ID

Se vuoi imporre un livello di profondità nella tua struttura, crea un trigger on-insert / update che genererà un'eccezione se questa query restituisce qualcosa.

SELECT *
FROM
  BRANCH B1
 ,BRANCH B2
 ,BRANCH B3
WHERE B1.PARENT_ID = :NEW.NEW_PARENT_ID
  AND B2.PARENT_ID = B1.BRANCH_ID
  AND B2.PARENT_ID = B3.BRANCH_ID;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top