Almacenar diferentes tipos en la misma columna a través de SQL_VARIANT
es casi lo mismo que enviar todo a Object
en .NET. Y a veces hay razones válidas para usar este tipo, ya que ciertamente puede permitir una estructura programática más genérica.
Sin embargo, a medida que estaban esperando, hay algunas trampas en el uso de SQL_VARIANT
que usted debe tener en cuenta, especialmente en lo que uno de ellos podría ser un acuerdo para romper:
Al igual que la fundición todo para Object
en .NET (y posiblemente requiera boxeo/unboxing dependiendo del tipo de base), hay un rendimiento definido al usar SQL_VARIANT
. Dependiendo del caso de uso, podría ser aceptable tener un rendimiento reducido si la funcionalidad realmente lo necesita y/o el uso no es muy frecuente (es decir, muchas veces por segundo).
A diferencia de la conversión de todo a Object
en .NET, el tipo de datos SQL_VARIANT
tiene limitaciones con respecto a los tipos de datos base que puede contener.Los siguientes tipos de datos no se pueden almacenar como SQL_VARIANT
:
VARCHAR(MAX)
NVARCHAR(MAX)
VARBINARY(MAX)
XML
TIMESTAMP
/ROWVERSION
TEXT
(que no deberían usar este tipo de todos modos como de SQL Server 2005)
NTEXT
(que no debe utilizar este tipo de todos modos como de SQL Server 2005)
IMAGE
(que no debe utilizar este tipo de todos modos como de SQL Server 2005)
Esta limitación se puede evitar fácilmente la posibilidad de usar SQL_VARIANT
si existe la necesidad de almacenar cualquiera de estos tipos de datos. Tenga en cuenta que la cuestión aquí es el tipo de datos base y no el tamaño de los datos, como la prueba siguiente muestra:
DECLARE @tmp1 TABLE (col1 SQL_VARIANT NOT NULL);
INSERT INTO @tmp1 (col1) VALUES (CONVERT(VARCHAR(MAX), 'g'));
Devuelve:
Msg 206, Level 16, State 2, Line 2
Operand type clash: varchar(max) is incompatible with sql_variant
Para ser justos, una beneficio de usar SQL_VARIANT
sobre la fundición de todo a NVARCHAR
es que SQL_VARIANT
conserva la información de tipo subyacente e impone su uso para que no pueda utilizar fácilmente los valores en contextos completamente inapropiados.
DECLARE @tmp2 TABLE (col1 SQL_VARIANT NOT NULL);
INSERT INTO @tmp2 (col1) VALUES (1);
SELECT CONVERT(DATETIME, col1) FROM @tmp2;
SELECT CONVERT(TIME, col1) FROM @tmp2;
Devuelve:
1900-01-02 00:00:00.000
Msg 529, Level 16, State 3, Line 6
Explicit conversion from data type int to time is not allowed.
En cuanto a no poder utilizar SQL_VARIANT
como PK: esto es realmente un no-problema ya que la naturaleza misma de un tipo de datos genérico más o menos lo excluye de ser deseable en el primer lugar para tal uso.
En cuanto a no poder utilizar SQL_VARIANT
con un operador LIKE
: esto es sobre todo un problema no debe de ser capaz de convertirlo a un tipo adecuado que funciona con LIKE
, como en:
WHERE CONVERT(NVARCHAR(50), [sql_variant_field]) LIKE '%something%'
Lo anterior ciertamente no es el más eficiente, pero es funcional, y como se mencionó anteriormente, la eficiencia ya se descartó ya que se sacrificó a cambio de la funcionalidad cuando se decidió utilizar el tipo de datos SQL_VARIANT
.
¿Por qué almacena diferentes tipos en la misma columna? ¿Es esto una estructura 'EAV'? –
No. Realmente no me quiero desviar de la validez de mi caso de uso, pero tengo una tabla de filtros que se puede aplicar a varias columnas. Por lo tanto, los valores comparables son de diferentes tipos. – Daniel