Pergunta

Estou usando o SQL Server 2005. Eu quero restringir os valores em uma coluna de ser único, permitindo NULLS.

Minha solução atual envolve um índice exclusivo em uma visão assim:

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)

idéias melhor?

Foi útil?

Solução

Pretty certeza que você não pode fazer isso, uma vez que viola o propósito de únicos.

No entanto, essa pessoa parece ter um trabalho decente em torno de: http://sqlservercodebook.blogspot.com /2008/04/multiple-null-values-in-unique-index-in.html

Outras dicas

Usando o SQL Server 2008, você pode criar um índice filtrado: http: / /msdn.microsoft.com/en-us/library/cc280372.aspx . (Eu vejo Simon adicionou-a como um comentário, mas achei que ele merecia a sua própria resposta como o comentário é facilmente perdida.)

Outra opção é um gatilho para verificar a unicidade, mas isso pode afetar o desempenho.

O truque coluna calculada é amplamente conhecido como um "nullbuster"; minha notas de crédito 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, uma coluna anulável único (ou conjunto de colunas) pode ser NULL (ou um registro de nulos) apenas uma vez, já que ter o mesmo valor (e isso inclui NULL) mais de uma vez, obviamente, viola a restrição exclusiva.

No entanto, isso não significa que o conceito de "colunas anuláveis ??únicas" é válido; para realmente implementá-lo em qualquer banco de dados relacional, só temos de ter em mente que este tipo de bases de dados são feitos para serem normalizados para adequadamente trabalho, e normalização envolve geralmente a adição de vários (não-entidade) mesas extras para estabelecer relações entre as entidades .

Vamos trabalhar um exemplo básico, considerando apenas uma "coluna anulável único", é fácil para expandi-lo para mais tais colunas.

Suponha que a informação representada por uma tabela como esta:

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

Podemos fazê-lo, colocando uniqnull à parte e adicionando uma segunda tabela para estabelecer uma relação entre os valores uniqnull e the_entity (em vez de ter 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)
);

Para associar um valor de uniqnull a uma linha na the_entity precisamos adicionar também uma linha em the_relation.

Para linhas em the_entity havia valores uniqnull estão associadas (ou seja, para os que iria colocar NULL em the_entity_incorrect) nós simplesmente não adicionar uma linha em the_relation.

Note que os valores para uniqnull será único para todos the_relation, e também notar que para cada valor em the_entity pode haver no máximo um valor em the_relation, já que as chaves primárias e estrangeiras sobre ele valer isso.

Então, se um valor de 5 para uniqnull deve ser associado a um ID de the_entity de 3, nós precisamos:

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

E, se um valor de ID de 10 para the_entity não tem contrapartida uniqnull, só fazemos:

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

Para desnormalizar esta informação e obter os dados de uma tabela como the_entity_incorrect iria realizar, precisamos:

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

A "junção externa esquerda" operador garanta todas as linhas da the_entity irá aparecer no resultado, colocando NULL na coluna uniqnull quando há colunas correspondentes estão presentes em the_relation.

Lembre-se, qualquer esforço despendido para alguns dias (ou semanas ou meses) na concepção de um banco de dados bem normalizada (e as correspondentes vistas desnormalizar e procedimentos) vai lhe poupar anos (ou décadas) de dor e desperdício de recursos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top