2012-02-27 15 views
8

Używam Microsoft SQL Server 2008 R2 (z najnowszymi dodatkami Service Pack/łatami), a sortowanie w bazie danych to SQL_Latin1_General_CP1_CI_AS.Zachowanie unikalnego indeksu, kolumny varchar i (puste) spacje

Następujący kod:

SET ANSI_PADDING ON; 
GO 

CREATE TABLE Test (
    Code VARCHAR(16) NULL 
); 
CREATE UNIQUE INDEX UniqueIndex 
    ON Test(Code); 

INSERT INTO Test VALUES ('sample'); 
INSERT INTO Test VALUES ('sample '); 

SELECT '>' + Code + '<' FROM Test WHERE Code = 'sample  '; 
GO 

daje następujące wyniki:

(1 rzędu (i) oddziaływania)

Msg 2601, poziom 14, w stanie 1, linia 8

Nie można wstawić duplikatu wiersza klucza w obiekcie "dbo.Test" z unikalnym indeksem "UniqueIndex". Zduplikowana wartość klucza to (przykład).

Oświadczenie zostało wypowiedziane.

‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐

> próbki <

(1 rząd (a) dotyczy)

My pytanie s to:

  1. Zakładam, że indeks nie może przechowywać spacji końcowych. Czy ktoś może wskazać mi oficjalną dokumentację, która określa/definiuje to zachowanie?
  2. Czy istnieje ustawienie do zmiany tego zachowania, to znaczy, aby rozpoznać "próbka" i "próbka" jako dwie różne wartości (którymi są, przy okazji), aby oba mogły znajdować się w indeksie.
  3. Dlaczego na ziemi SELECT zwraca wiersz? SQL Server musi robić coś naprawdę zabawnego/sprytnego ze spacjami w klauzuli WHERE, ponieważ jeśli usuniemy unikalność indeksu, oba INSERT uruchomią się poprawnie, a SELECT zwróci dwa wiersze!

Każda pomoc/wskaźnik we właściwym kierunku zostanie doceniona. Dzięki.

Odpowiedz

11

Trailing blanks explained:

SQL Server następuje SQL-92 specyfikacja ANSI/ISO (sekcja 8.2 , Zasady ogólne nr 3) w jaki sposób porównać ciągi ze spacjami. Norma ANSI wymaga dopełnienia dla ciągów znakowych używanych w porównaniach, aby ich długości były zgodne przed porównaniem ich. Wypełnienie ma bezpośredni wpływ na semantykę WHERE i predykaty klauzula HAVING oraz inne porównania w języku Transact-SQL string: . Na przykład Transact-SQL traktuje ciągi "abc" i "abc" jako równoważne dla większości operacji porównania.

Jedynym wyjątkiem od tej reguły jest predykat LIKE.Kiedy właściwa strona z wyrażeniem predykatu LIKE ma wartość z końcową przestrzenią , SQL Server nie umieszcza obu wartości na tej samej długości , zanim nastąpi porównanie. Ponieważ celem predykatu LIKE jest, z definicji, ułatwienie wyszukiwania wzorców, a nie niż proste testy równości łańcuchowej, nie narusza to sekcji wspomnianej wcześniej specyfikacji ANSI SQL-92.

Oto znany przykład z wszystkich wyżej wymienionych przypadkach:

DECLARE @a VARCHAR(10) 
DECLARE @b varchar(10) 

SET @a = '1' 
SET @b = '1 ' --with trailing blank 

SELECT 1 
WHERE 
    @a = @b 
AND @a NOT LIKE @b 
AND @b LIKE @a 

Oto kilka szczegółów na temat trailing blanks and the LIKE clause.

Jeśli chodzi o indeksy:

wstawka do kolumny, których wartości muszą być unikalne zawiedzie, jeśli dostarczyć wartość, która różni się od istniejących wartości przez spływu tylko spacje. Poniższe ciągi będą uważane za równoważne przez jednoznaczne ograniczenie, klucz podstawowy lub unikalny indeks. Podobnie, jeśli masz istniejącą tabelę z danymi poniżej i spróbuj dodać unikalne ograniczenie, nie powiedzie się, ponieważ wartości są za identyczne.

PaddedColumn 
------------ 
'abc' 
'abc ' 
'abc ' 
'abc ' 

(Taken from here).

+2

Dzięki za wskazówki, chłopaki. Mea culpa za to, że sam jestem zbyt leniwy dla Google'a. Moim zdaniem zachowanie zdefiniowane przez standard nie jest intuicyjne. Wyobrażam sobie, że 9 na 10 programistów powie, że "a" i "a" NIE są tym samym ciągiem, ale no cóż. – Eric

Powiązane problemy