Domanda

Sto usando SQL Server 2005. Voglio vincolare i valori in una colonna per essere univoci, consentendo NULLS.

La mia attuale soluzione prevede un indice univoco in una vista come questa:

CREATE VIEW vw_unq WITH SCHEMABINDING AS
    SELECT Column1
      FROM MyTable
     WHERE Column1 IS NOT NULL

CREATE UNIQUE CLUSTERED INDEX unq_idx ON vw_unq (Column1)

Qualche idea migliore?

È stato utile?

Soluzione

Abbastanza sicuro che non puoi farlo, in quanto viola lo scopo degli unici.

Tuttavia, questa persona sembra avere un lavoro decente in giro: http://sqlservercodebook.blogspot.com /2008/04/multiple-null-values-in-unique-index-in.html

Altri suggerimenti

Utilizzando SQL Server 2008, è possibile creare un indice filtrato: http: / /msdn.microsoft.com/en-us/library/cc280372.aspx. (Vedo che Simon ha aggiunto questo come commento, ma ho pensato che meritasse la sua risposta poiché il commento è facilmente perso.)

Un'altra opzione è un trigger per verificare l'unicità, ma ciò potrebbe influire sulle prestazioni.

Il trucco della colonna calcolato è ampiamente noto come "nullbuster"; le mie note di merito Steve Kass:

CREATE TABLE dupNulls (
pk int identity(1,1) primary key,
X  int NULL,
nullbuster as (case when X is null then pk else 0 end),
CONSTRAINT dupNulls_uqX UNIQUE (X,nullbuster)
)

A rigor di termini, una colonna nullable unica (o un insieme di colonne) può essere NULL (o un record di NULL) solo una volta, poiché avere lo stesso valore (e questo include NULL) più di una volta ovviamente viola il vincolo univoco.

Tuttavia, ciò non significa che il concetto di "uniche colonne Nullble". è valido; per implementarlo effettivamente in qualsiasi database relazionale, dobbiamo solo tenere presente che questo tipo di database deve essere normalizzato per funzionare correttamente e la normalizzazione di solito comporta l'aggiunta di diverse tabelle extra (non entità) per stabilire relazioni tra le entità .

Facciamo un esempio di base considerando solo una "colonna nullable unica", è facile espanderlo in più colonne di questo tipo.

Supponiamo che le informazioni rappresentate da una tabella come questa:

create table the_entity_incorrect
(
  id integer,
  uniqnull integer null, /* we want this to be "unique and nullable" */
  primary key (id)
);

Possiamo farlo mettendo uniqnull a parte e aggiungendo una seconda tabella per stabilire una relazione tra valori uniqnull e the_entity (piuttosto che avere uniqnull " dentro " the_entity):

create table the_entity
(
  id integer,
  primary key(id)
);

create table the_relation
(
  the_entity_id integer not null,
  uniqnull integer not null,

  unique(the_entity_id),
  unique(uniqnull),
  /* primary key can be both or either of the_entity_id or uniqnull */
  primary key (the_entity_id, uniqnull), 
  foreign key (the_entity_id) references the_entity(id)
);

Per associare un valore di uniqnull a una riga in the_entity dobbiamo anche aggiungere una riga in the_relation.

Per le righe in the_entity in cui non sono associati valori uniqnull (ovvero per quelli che inseriremmo NULL in the_entity_incorrect) semplicemente non aggiungiamo una riga in the_relation.

Nota che i valori per uniqnull saranno univoci per tutta the_relation, e nota anche che per ogni valore in the_entity può esserci al massimo un valore in the_relation, poiché le chiavi primarie ed esterne su di essa lo applicano.

Quindi, se un valore di 5 per uniqnull deve essere associato a un id the_entity di 3, dobbiamo:

start transaction;
insert into the_entity (id) values (3); 
insert into the_relation (the_entity_id, uniqnull) values (3, 5);
commit;

E, se un valore id di 10 per the_entity non ha una controparte uniqnull, lo facciamo solo:

start transaction;
insert into the_entity (id) values (10); 
commit;

Per denormalizzare queste informazioni e ottenere i dati contenuti in una tabella come the_entity_incorrect, è necessario:

select
  id, uniqnull
from
  the_entity left outer join the_relation
on
  the_entity.id = the_relation.the_entity_id
;

Il " join esterno sinistro " L'operatore assicura che tutte le righe di the_entity vengano visualizzate nel risultato, inserendo NULL nella colonna uniqnull quando non sono presenti colonne corrispondenti in the_relation.

Ricorda, qualsiasi sforzo speso per alcuni giorni (o settimane o mesi) nella progettazione di un database ben normalizzato (e le corrispondenti viste e procedure denormalizzanti) ti farà risparmiare anni (o decenni) di dolore e risorse sprecate.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top