Buscar un valor en columnas seleccionadas
Conocemos un nombre, correo o referencia, pero no recordamos en cuál de varias columnas de texto se guardó. Generar una búsqueda sobre toda la base sería costoso y podría leer información que no necesitamos.
Qué necesitamos distinguir
Una lista autorizada limita de antemano qué columnas pueden consultarse. QUOTENAME delimita un identificador de forma válida; un parámetro envía el valor separado del SQL dinámico, que es código construido durante la ejecución.
Definiremos primero una lista explícita de columnas autorizadas. Los identificadores se delimitarán con QUOTENAME y el valor se enviará como parámetro; así evitamos concatenar el dato buscado dentro del SQL dinámico.
Consulta
/*
Antes de ejecutar:
Revisa la base activa, los nombres de objetos, los parámetros y los permisos.
Adapta el ejemplo a tu modelo y pruébalo primero en un ambiente controlado.
*/
SET NOCOUNT ON;
GO
-- Consulta
DECLARE @Valor NVARCHAR(200) = N'Pedido 1';
DECLARE @CoincidenciaExacta BIT = 0;
DECLARE @Patron NVARCHAR(450);
DECLARE @Sql NVARCHAR(MAX);
DECLARE @Columnas TABLE
(
Esquema SYSNAME,
Tabla SYSNAME,
Columna SYSNAME,
PRIMARY KEY (Esquema, Tabla, Columna)
);
INSERT INTO @Columnas (Esquema, Tabla, Columna)
VALUES
(N'dbo', N'Cliente', N'Nombre'),
(N'dbo', N'Cliente', N'Correo'),
(N'dbo', N'MovimientoInventario', N'Referencia');
IF EXISTS
(
SELECT 1
FROM @Columnas AS x
WHERE NOT EXISTS
(
SELECT 1
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON s.schema_id = t.schema_id
INNER JOIN sys.columns AS c
ON c.object_id = t.object_id
WHERE s.name = x.Esquema
AND t.name = x.Tabla
AND c.name = x.Columna
AND c.system_type_id IN
(TYPE_ID(N'char'), TYPE_ID(N'varchar'),
TYPE_ID(N'nchar'), TYPE_ID(N'nvarchar'))
)
)
THROW 50020, N'La lista contiene una columna inexistente o no textual.', 1;
SET @Patron = CASE
WHEN @CoincidenciaExacta = 1 THEN @Valor
ELSE N'%' +
REPLACE(REPLACE(REPLACE(REPLACE
(@Valor, N'\', N'\\'), N'%', N'\%'), N'_', N'\_'), N'[', N'\[') +
N'%'
END;
SELECT @Sql = STRING_AGG
(
CAST
(
N'SELECT N' + QUOTENAME(x.Esquema, '''') + N' AS Esquema, ' +
N'N' + QUOTENAME(x.Tabla, '''') + N' AS Tabla, ' +
N'N' + QUOTENAME(x.Columna, '''') + N' AS Columna, ' +
N'CONVERT(nvarchar(4000), ' + QUOTENAME(x.Columna) +
N') AS ValorEncontrado FROM ' + QUOTENAME(x.Esquema) + N'.' +
QUOTENAME(x.Tabla) + N' WHERE CONVERT(nvarchar(4000), ' +
QUOTENAME(x.Columna) + N') ' +
CASE WHEN @CoincidenciaExacta = 1
THEN N'= @Patron'
ELSE N'LIKE @Patron ESCAPE N''\'''
END
AS NVARCHAR(MAX)
),
N' UNION ALL '
)
FROM @Columnas AS x;
EXEC sys.sp_executesql
@Sql,
N'@Patron nvarchar(450)',
@Patron = @Patron;
GO
Parámetros o permisos
Cambia @Valor y las filas de @Columnas. La búsqueda se limita a tipos de texto y a los primeros 4,000 caracteres convertidos; para columnas max con documentos extensos conviene diseñar otra estrategia. QUOTENAME protege nombres de esquema, tabla y columna; no sustituye la parametrización de valores. sp_executesql recibe @Patron por separado. Se requieren permisos de lectura sobre todas las columnas seleccionadas y visibilidad de sus metadatos.
Cómo leer el resultado
Cada coincidencia indica esquema, tabla, columna y valor encontrado. En modo parcial escapamos , %, _ y [ para tratarlos como caracteres del texto y no como comodines de LIKE. STRING_AGG construye una consulta por columna y las une con UNION ALL. Aunque los identificadores estén delimitados, cada columna seleccionada puede requerir un escaneo si no existe una estrategia de búsqueda adecuada. La comparación utiliza la intercalación de cada columna. Por eso sensibilidad a mayúsculas, acentos y otros caracteres puede variar entre tablas.
Qué conclusión sí permite obtener
Permite localizar un valor en un conjunto explícito y revisable de columnas textuales sin insertar el valor directamente en el SQL dinámico.
Qué conclusión todavía no permite obtener
No busca automáticamente en toda la base, no cubre binarios ni compara números o fechas con su tipo original. Tampoco garantiza buen rendimiento sobre tablas grandes o búsquedas parciales con comodín inicial.
Siguiente comprobación razonable
Si una columna concentra búsquedas recurrentes, revisa su modelo de acceso y evita convertir esta consulta de investigación en una operación habitual de la aplicación.