2012-02-27 19 views
8

Estoy usando Microsoft SQL Server 2008 R2 (con el último Service Pack/parches) y la recopilación de la base de datos es SQL_Latin1_General_CP1_CI_AS.Comportamiento de índice único, columna varchar y espacios (en blanco)

el siguiente código:

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 

produce los siguientes resultados:

(1 fila (s) afectada)

Msg 2601, nivel 14, estado 1, línea 8

No se puede insertar una fila de clave duplicada en el objeto 'dbo.Test' con el índice único 'UniqueIndex'. El valor duplicado de la clave es (muestra).

La declaración ha finalizado.

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

> muestra <

(1 fila (s) afectada)

Mi pregunta s son:

  1. Supongo que el índice no puede almacenar espacios finales. ¿Alguien puede indicarme documentación oficial que especifique/defina este comportamiento?
  2. Hay una configuración para cambiar este comportamiento, es decir, hacer que reconozca 'muestra' y 'muestra' como dos valores diferentes (que son, por cierto) para que ambos puedan estar en el índice.
  3. ¿Por qué en la Tierra es el SELECTO que devuelve una fila? SQL Server debe estar haciendo algo realmente divertido/inteligente con los espacios en la cláusula WHERE porque si elimino la exclusividad en el índice, ambos INSERT correrán OK y el SELECT devolverá dos filas.

Cualquier ayuda/puntero en la dirección correcta sería apreciada. Gracias.

Respuesta

11

Trailing blanks explained:

SQL Server sigue la especificación ANSI/ISO-92 (Sección 8.2, , normas generales # 3) sobre la forma de comparar cadenas con espacios. El estándar ANSI requiere relleno para las cadenas de caracteres utilizadas en las comparaciones de modo que sus longitudes coincidan antes de comparándolas. El relleno afecta directamente a la semántica de WHERE y los predicados de cláusula HAVING y otras comparaciones de cadenas de Transact-SQL . Por ejemplo, Transact-SQL considera que las cadenas 'abc' y 'abc' son equivalentes para la mayoría de las operaciones de comparación.

La única excepción a esta regla es el predicado LIKE.Cuando el lado derecho de una expresión de predicado LIKE presenta un valor con un espacio posterior, SQL Server no llena los dos valores con la misma longitud antes de que se produzca la comparación. Dado que el propósito del predicado LIKE , por definición, es facilitar las búsquedas de patrones en lugar de las simples pruebas de igualdad de cadenas en lugar de , esto no infringe la sección de la especificación ANSI SQL-92 mencionada anteriormente.

Aquí está un ejemplo bien conocido de todos los casos mencionados anteriormente:

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 

Aquí hay más detalles sobre trailing blanks and the LIKE clause.

En cuanto a los índices:

una inserción en una columna cuyos valores deben ser únicos fallará si se suministra un valor que se diferencia de los valores existentes por sólo espacios finales. Las siguientes cadenas se considerarán equivalentes por una restricción única, clave principal o índice único. Del mismo modo, si tiene una tabla existente con los datos a continuación y trata de agregar una restricción única, fallará porque los valores son considerados idénticos.

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

(Tomado de here.)

+2

Gracias por los punteros, chicos. Mea culpa por ser demasiado perezoso para Google eso solo. En mi opinión, el comportamiento definido por el estándar no es intuitivo. Me imagino que 9 de cada 10 desarrolladores dirían que 'a' y 'a' NO son la misma cadena, pero bueno. – Eric

Cuestiones relacionadas