Buscar texto dentro de procedimientos almacenados

Muchas veces hacemos uso de los procedimientos almacenados para realizar ciertas funciones sobre nuestra base de datos, desde operaciones de actualización, consulta, etc., hasta algunas actividades más complejas.

En ocaciones tenemos cientos o más de procedimientos almacenados y nunca falta un cambio sobre nuestra base de datos (por ejemplo, agregar una columna a una tabla) que nos obliga a revisar todos nuestros procedimientos para actualizarlos con el nuevo cambio. Cuando se tiene una documentación actualizada de la base de datos y por ende, de los procedimientos almacenados solo falta con echarle un vistazo para saber que procedimientos deben ser actualizados... pero muy raras veces - de hecho casi siempre ;) - no se cuenta con dicha documentación o no esta actualizada.

Cuando estamos ante esta situación podemos auxiliarnos con el siguiente código, el cual hace uso de syscomments (aquí se almacena el texto de los procedimientos almacenados, funciones, triggers, etc.) para realizar una búsqueda de un texto en específico dentro de todos los procedimientos y funciones de una base de datos especificada.


--La base de datos en la que se buscará
USE DBData
GO
--Variable que contentendrá el texto a buscar, nombre de una tabla, columna, etc...
DECLARE @SearchText AS VARCHAR(100)
SET @SearchText = 'Tabla1'
--Consulta de los procedimeintos que contienen dicho texto
SELECT DISTINCT USER_NAME(o.uid) + '.' + OBJECT_NAME(c.id) AS 'Object name',
CASE
WHEN OBJECTPROPERTY(c.id, 'IsReplProc') = 1
THEN 'Replication stored procedure'
WHEN OBJECTPROPERTY(c.id, 'IsExtendedProc') = 1
THEN 'Extended stored procedure'
WHEN OBJECTPROPERTY(c.id, 'IsProcedure') = 1
THEN 'Stored Procedure'
WHEN OBJECTPROPERTY(c.id, 'IsTrigger') = 1
THEN 'Trigger'
WHEN OBJECTPROPERTY(c.id, 'IsTableFunction') = 1
THEN 'Table-valued function'
WHEN OBJECTPROPERTY(c.id, 'IsScalarFunction') = 1
THEN 'Scalar-valued function'
WHEN OBJECTPROPERTY(c.id, 'IsInlineFunction') = 1
THEN 'Inline function'
WHEN OBJECTPROPERTY(c.id, 'IsView') = 1
THEN 'View'
END AS 'Object type'
FROM syscomments c
INNER JOIN
sysobjects o
ON c.id = o.id
WHERE c.text LIKE '%'+@SearchText+'%' AND
encrypted = 0 AND
( OBJECTPROPERTY(c.id, 'IsReplProc') = 1 OR
OBJECTPROPERTY(c.id, 'IsExtendedProc') = 1 OR
OBJECTPROPERTY(c.id, 'IsProcedure') = 1 OR
OBJECTPROPERTY(c.id, 'IsTrigger') = 1 OR
OBJECTPROPERTY(c.id, 'IsTableFunction') = 1 OR
OBJECTPROPERTY(c.id, 'IsScalarFunction') = 1 OR
OBJECTPROPERTY(c.id, 'IsInlineFunction') = 1 OR
OBJECTPROPERTY(c.id, 'IsView') = 1 )
ORDER BY [Object type], 'Object name'


De esta manera obtendremos el nombre de todos los procedimientos, funciones y triggers que dentro de sí contienen la palabra definida en @SearchText.

Esto me ha ayudado muchísimo en mi trabajo y espero que a alguien más le sirva.

Saludos y si tienen algún comentario para este o cualquier otro post en este blog no duden en escribirlo. :)

Comparar cadenas en SQL sin distinguir el acento

Cuando necesitamos buscar registros en una base de datos de SQL Server un texto que el usuario ingresó en nuestra aplicación suele ser muy útil no considerar los acentos en dicha búsqueda, especialmente si hablamos de nombres o apellidos de personas.

Por ejemplo si tenemos la siguiente consulta y utilizamos "San" como valor de entrada:

SELECT Nombre, ApellidoPaterno, ApellidoMaterno
FROM Empleados
WHERE ApellidoPaterno LIKE '%' + @Valor +'%'


Esto NO nos devolvería los empleados con apellidos cómo "Sánchez". Para arreglar esta situacion simplemente indicamos que la comparación (LIKE) debería hacerse utilizado una intercalación especifica, una que no sea sensible a los acentos. Entonces:

SELECT Nombre, ApellidoPaterno, ApellidoMaterno
FROM Empleados
WHERE ApellidoPaterno LIKE '%' + @Valor +'%' COLLATE SQL_LATIN1_GENERAL_CP1_CI_AI


Con esto solucionamos el problema y con el valor establecido a "San" obtendríamos entre los resultados a "Sánchez", "Sandoval", etc.

Desempeño en el acceso a datos

Algunos tips útiles para mejorar el desempeño de nuestras aplicaciones al obtener datos desde la base de datos se pueden encontrar en el blog de: Adam Machanic y Noel Watson.

Establecer datos a un reporte en Crystal Reports .NET

Para establecer los datos a un reporte en Crystal Reports .NET (es decir el métdo PUSH) se puede utilizar el método SetDataSource() del objeto ReportDocument. Sin embargo, si se está utilizando un Dataset que tiene varias tablas enlazadas, hay que tener mucho cuidad con el orden en como se establecen los datos así como en los nombres de las tablas del Dataset que tienen que coincidir exactamente.

Para evitarnos problemas lo mejor es establecer los datos directamente a cada tabla. Esto se puede lograr mediante la propiedad Database del objeto ReportDocument el cual contiene a su vez una colección de objetos Table (de CrystalDecisions.CrystalReports.Engine.Table). Esta colección contiene las tablas que se definieron en el reporte durante el diseño. Cada una de estos objetos Table define un método SetDataSource() para llenar los datos de esa tabla en específico. Por lo tanto se puede hacer lo siguiente:

Dataset dts = new Dataset();
// ... obtener los datos para el reporte
ReportDocument rpt = new MiReporte();
rpt.Database.Tables["tabla1"].SetDataSource(dts.Tables["tabla1"]);
rpt.Database.Tables["tabla2"].SetDataSource(dts.Tables["tabla2"]);
rpt.Database.Tables["tabla3"].SetDataSource(dts.Tables["tabla3"]);
CrystalReportViewer.ReportSource = rpt;