tag:blogger.com,1999:blog-18555635623078702542024-03-05T04:28:24.493-05:00Programación Visual Basic con Sql ServerVisual Basic, es un tema trillado. Hay mas de 100 000 sitios que hablan y viven del Visual Basic. Me agrego a esa lista, para hablar de mi experiencia con este lenguaje de programación y lo que es necesario para acceder a un gestor de base de datos como es Sql Server.Unknownnoreply@blogger.comBlogger60125tag:blogger.com,1999:blog-1855563562307870254.post-11452415356785902952012-08-28T16:28:00.000-05:002012-08-28T16:28:51.215-05:00Ejecutar Scripts Sql Server con C# y Visual Basic.NETEn este artículo veremos como se puede ejecutar un Script SQL Server para realizar una copia de seguridad utilizando C# en Visual Studio con la ayuda de SQLCMD.
SQLCMD es la línea de comandos de SQL Server. Esta línea de comandos nos permite ejecutar scripts T-SQL. SQLCMD es un método rápido y sencillo de ejecutar scripts.
En Visual Studio estaremos llamando a SQLCMD utilizando la clase ProcessStartInfo. Esta clase es utilizada para iniciar procesos. En este código vamos a llamar al proceso SQLCMD. Al final del artículo tendrán una aplicación de ejmplo con un botón con una llamada a un script .sql. En este caso, el script generará una copia de seguridad de la base de datos:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn5lXMFyfrIGdv5OXqxd_uMaE49-IDadUGLx5wdYjOM3h_H3-QwBqnLDt_Y0zFRnHFv4w6cwDajiNnQ966-u5VD72JtvgSJ2u8Br46JX1dfTMCoIaG7jBVwr-a56Zp1fO-eKWTCOktnZZA/s1600/script+sql+server+c%23.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn5lXMFyfrIGdv5OXqxd_uMaE49-IDadUGLx5wdYjOM3h_H3-QwBqnLDt_Y0zFRnHFv4w6cwDajiNnQ966-u5VD72JtvgSJ2u8Br46JX1dfTMCoIaG7jBVwr-a56Zp1fO-eKWTCOktnZZA/s1600/script+sql+server+c%23.png" /></a></div>
El botón "llamar a SQLCMD" creará una copia de seguridad utilizando la clase ProcessStartInfo. Para mayor referencia acerca de la clase ProcessStartInfo, el sqlcmd y ejecución scripts con sqlcmd puedes leer <a href="http://msdn.microsoft.com/es-es/library/ms162773.aspx" target="_blank">aquí</a>.<br />
<br />
Los archivos incluídos: pruebas.zip es la copia de seguridad de la base de datos y callSQLcmd.zip es el proyecto en Visual Studio 2010 para c# y Vb.NET.<br />
<br />
<span style="font-size: large;"><b>Demostración</b></span><br />
<br />
Primero que todo hay que crear un script llamado backup.sql para realizar la copia de seguridad de la base de datos. El nombre del script es backup.sql y contiene:<br />
<br />
<div style="background-color: #ffe599;">
<br />
BACKUP DATABASE [Pruebas] TO DISK = N'C:\backup\pruebas.bak'
WITH NOFORMAT, NOINIT, NAME = N'test-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10<br />
GO</div>
<br />
<br />
Este script creará una copia de seguridad de la base de datos de prueba. Para ejecutar el script backup.sql utilizando sqlcmd, ve a la ventana de línea de comandos y ejecuta la siguiente sentencia:<br />
<br />
<div style="background-color: #ffe599;">
<br /></div>
<div style="background-color: #ffe599;">
sqlcmd -S .\sqlexpress -i C:\backup.sql </div>
<div style="background-color: #ffe599;">
<br /></div>
<div style="background-color: #ffe599;">
o</div>
<div style="background-color: #ffe599;">
<br /></div>
<div style="background-color: #ffe599;">
sqlcmd -S Usuario-PC -i C:\backup.sql </div>
<div style="background-color: #ffe599;">
<br /></div>
<br />
<b><span style="font-size: large;">Explicación</span></b><br />
<br />
-S .\sqlexpress (la –S está en mayúsculas) indica el nombre del servidor. En este caso es la máquina local y una instancia SQL Server Express. Por ejemplo, si estás utilizando la instancia por defecto y el nombre del servidor es Server1 y el dominio del Directorio Activo es llamado sqlcentral, la línea de comandos podría ser:<br />
<br />
<div style="background-color: #ffe599;">
<br /></div>
<div style="background-color: #ffe599;">
sqlcmd -S sqlcentral\Server1 -i C:\backup.sql
-i c:\backup.sql </div>
<div style="background-color: #ffe599;">
<br /></div>
<br />
El parametro -i es la entrada (es en minúsculas) y c:\backup.sql es la ruta del script. Por defecto se utiliza la autentificación por Windows.<br />
<br />
<span style="font-size: large;"><b>Utilizando un Windows Form en C# para llamar a SQLCMD</b></span><br />
<br />
Tenemos una línea de comandos SQL que crea una copia de seguridad de SQL Server. Ahora vamos a crear una aplicación Windows en C# que llame a SQLCMD. Dentro del formulario arrastraremos un botón desde el cuadro de Herramientas de Visual Studio. El botón llamará a la línea de comandos sqlcmd para crear la copia de seguridad llamada test utilizando sqlcmd. Haz doble click en el botón y agrega el siguiente código:<br />
<br />
<div style="background-color: #ffe599;">
<br /></div>
<div style="background-color: #ffe599;">
using System.Diagnostics; </div>
<div style="background-color: #ffe599;">
<br /></div>
<br />
También:<br />
<br />
<br />
<div style="background-color: #ffe599;">
<br /></div>
<div style="background-color: #ffe599;">
// Indica si el cursor del sistema operativo es utilizado, en este caso no</div>
<div style="background-color: #ffe599;">
UseShellExecute = false; </div>
<div style="background-color: #ffe599;">
//ninguna ventana nueva es requerida</div>
<div style="background-color: #ffe599;">
info.CreateNoWindow = true; </div>
<div style="background-color: #ffe599;">
//The windows style will be hidden </div>
<div style="background-color: #ffe599;">
info.WindowStyle = ProcessWindowStyle.Hidden; </div>
<div style="background-color: #ffe599;">
//The output will be read by the starndar output process </div>
<div style="background-color: #ffe599;">
info.RedirectStandardOutput = true; </div>
<div style="background-color: #ffe599;">
Process proc = new Process(); </div>
<div style="background-color: #ffe599;">
proc.StartInfo = info; </div>
<div style="background-color: #ffe599;">
//Start the process </div>
<div style="background-color: #ffe599;">
proc.Start();</div>
<div style="background-color: #ffe599;">
<br /></div>
<br />
The most important section of the code is the following:<br />
<br />
<div style="background-color: #ffe599;">
<br /></div>
<div style="background-color: #ffe599;">
ProcessStartInfo info = new ProcessStartInfo("sqlcmd", @" -S -i C:\backup\backup.sql"); </div>
<div style="background-color: #ffe599;">
<br /></div>
<br />
En esta sección estamos llamando a sqlcmd y ejecutando el script backup.sql utilizando la clase processStartInfo. Es el núcleo del código. El resto es solo la configuración nde los parámetros del proceso. El código está llamando a la instancia del servidor SQL Express utilizando el parametro -S. El parámetro -i es la entrada. En este ejemplo la entrada es el script backup.sql. La autentificación utilizada es la autentificación por Windows, mientras el usuario que ejecute la aplicación tenga permisos en la base de datos, no habrá problemas.<br />
<br />
<span style="font-size: large;"><b>Probando tu código</b></span> <br />
<br />
Ahora presiona el botón Ejecutar en Visual Studio y haz click en el botón del formulario. Una nueva copia de seguridad debería crearse en c:\backup. <br />
<br />
<br />
<span style="font-size: large;"><b>Conclusión</b></span><br />
<br />
En este artículo vemos como llamar a sqlcmd y ejecutar un script Sql utilizando visual studio.<br />
<br />
<span style="font-size: large;"><b>Recursos</b></span><br />
<br />
<a href="https://docs.google.com/open?id=0B5_30LSb1dXsMFNSOHVGX3M0VVU" target="_blank">Descarga ejemplo para C# </a><br />
<a href="https://docs.google.com/open?id=0B5_30LSb1dXsNTg1bG00a0FULWM" target="_blank">Descarga ejemplo para Vb.NET</a><br />
<a href="https://docs.google.com/open?id=0B5_30LSb1dXsbDUycUlVWDdacDQ" target="_blank">Copia de seguridad Pruebas</a>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1855563562307870254.post-16036415437281760702012-08-19T19:41:00.001-05:002012-08-19T19:41:52.853-05:0011 Consejos para Hacer Copias de Seguridad con SMO, VB, C# PowerShell y Línea de Comandos<h4>Introducción </h4> <p>Algunas veces necesitamos crear copias de seguridad utilizando código, y necesitamos hacerlo de forma manual o automática, o tal vez programáticamente utilizando C#, VB, Powershell. Este tutorial te enseñará 11 formas de hacerlo. </p> <h5><strong>Consejo 1: La copia de seguridad simple</strong></h5> <p>La forma más sencilla de crear una copia de seguridad es utilizando el SQL Server Management Studio (Administrador Corporativo) con un click derecho en la base de datos y seleccionado Tasks (Tareas)>Backup (Copia de Seguridad). </p> <p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15312.jpg" /></p> <p>Puedes elegir la ruta por defecto para realizar la copia de seguridad y especificar otras opciones de la copia de seguridad en el diálogo que aparece. </p> <p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15313.jpg" /></p> <h5><strong>Consejo 2: Generar código T-SQL para realizar la copia de seguridad automáticamente</strong></h5> <p>Para generar el código T-SQL, necesitas utilizar la opción del menú Script Action to New Query Window (Nueva Ventana de Consulta) o to File (Archivo) o Clipboard (Portapapeles).  Estas opciones generaran el código T-SQL para realizar la copia de seguridad automáticamente. </p> <p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15325.jpg" /></p> <p>El código creado automáticamente: </p> <pre>BACKUP DATABASE [test] TO DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Backup\test.bak' WITH NOFORMAT, NOINIT, NAME = N'test-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10<br /><br />GO</pre><br /><br /><h5><strong>Consejo 3: Copia de seguridad utilizando la línea de comandos</strong></h5><br /><br /><p>Algunas veces necesitamos utilizar la línea de comandos para realizar la copia de seguridad. Para esos casos, puedes utilizar la utilidad sqlcmd que viene con SQL Server. Para iniciarla, en una ventana de línea de comandos ejecuta el comando SQLCMD. En una máquina local la utiliza se conectará a la instancia, en otro caso deberías especificar el nombre del servidor de la siguiente forma: </p><br /><br /><pre><strong>Sqlcmd –S dominio\nombreinstancia</strong></pre><br /><br /><p>Para realizar la copia de seguridad de la base de datos estariamos utilizando el T-SQL que generamos en el Consejo 2, en un archivo llamado sqlbackup.sql.Para ejecutar el script ejecuta este comando en la ventana de línea de comandos: </p><br /><br /><pre><strong>Sqlcmd –i c:\sqlbackup.sql</strong></pre><br /><br /><p>Este comando ejecuta el archivo .sql y crea una copia de seguridad. </p><br /><br /><h5><strong>Consejo 4: Crea una copia de seguridad programada utilizando Jobs del mismo SQL Server</strong></h5><br /><br /><p>Los jobs o trabajos nos dejan programar diferentes tareas para administración y mantenimiento. Puede programar que una copia de seguridad se realice diariamente a una hora especifica. La forma más fácil de hacerlo es seleccionar "Script Action to Job" en la ventana mencionada en Consejo 1. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15324.jpg" /></p><br /><br /><p>El trabajo es creado automáticamente. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15323.jpg" /></p><br /><br /><p>Y puedes especificar la programación en la que se realizará la copia de seguridad. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15322.jpg" /></p><br /><br /><h5></h5><br /><br /><h5><strong>Consejo 5: Programar una copia de seguridad sin el SQL Agent</strong></h5><br /><br /><p>Alguna veces solo tienes la edición SQL Express, la cual no incluye el SQL Agent. En este caso puedes utilizar el Consejo 3 dentro de un archivo por lotes como el siguiente: </p><br /><br /><p>Nombre de Archivo:Backup.bat </p><br /><br /><pre><strong>Sqlcmd –i c:\sqlbackup.sql</strong></pre><br /><br /><p>Luego puedes utilizar el programador de tareas que viene con el sistema operativo Windows y llamar el archivo .bat. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15321.jpg" /></p><br /><br /><h5></h5><br /><br /><h5><strong>Consejo 6: Crear una copia de seguridad utilizando PowerShell</strong></h5><br /><br /><p>PowerShell es una herramienta muy poderosa que puede ser utilizada para tareas administrativas automatizadas relacionadas con el sistema operativo, bases de datos, servidor web, servidor de correo, etc. Es algo bastante útil que con unas cuantas líneas de código nos hace la vida más sencilla. </p><br /><br /><p>Para iniciar PowerShell, haz click derecho en Databases (Bases de datos) en el SQL Server Management Studio y selecciona Iniciar Powershell. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15320.jpg" /></p><br /><br /><p>Necesitaremos el archivo sqlbackup1.sql creado en el consejo 3. Para invocar el script SQL con PowerShell, ejecuta la siguiente línea: </p><br /><br /><pre><strong>Invoke-Sqlcmd -InputFile "C:\sqlbackup1.sql"</strong></pre><br /><br /><h5><strong>Consejo 7: El asistente de Planes de Mantenimiento (Maintenance plan wizard)</strong></h5><br /><br /><p>SQL Server trae incluído un asistente para generar copias de seguridad, mantenimiento de índices, reducir bases de datos, etc. Para iniciar el asistente, vamos a Management>Maintenance Plan y seleccionamos el Maintenance Plan Wizard. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15319.jpg" /></p><br /><br /><p>Puedes revisar la integridad de bases de datos, reducir, reorganizar índices, etc. En este caso queremos ejecutar la copia de seguridad de una base de datos. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15318.jpg" /></p><br /><br /><p>Puedes seleccionar múltiples bases de datos para realizar la copia de seguridad desde este diálogo.</p><br /><br /><p><strong>Consejo 8: El Plan de Mantenimiento</strong></p><br /><br /><p>Algunas veces necesitamos personalizar un plan de mantenimiento y el asistente no nos puede ayudar lo suficiente. En este caso creamos un nuevo plan de mantenimiento (maintenance plan). </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15317.jpg" /></p><br /><br /><p>Esta herramienta te deja crear tareas y puedes conectar las tareas gráficamente. Puedes cambiar el orden de las tareas cuando sean ejecutadas o ejecutar diferentes tareas en caso una falle. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15316.jpg" /></p><br /><br /><h5></h5><br /><br /><h5><strong>Consejo 9: SQL Server Data Tools</strong></h5><br /><br /><p>Si tienes SQL Server 2008 o 2005 esta aplicación se llama SQL Server Business Intelligence (BIDS), pero en SQL Server 2012 fue renombrada a SQL Server Data Tools. </p><br /><br /><p><img border="0" alt="" src="http://www.sqlservercentral.com/Images/15315.jpg" /></p><br /><br /><p>En SSDT, puedes abrir un Integration Service Project y luego puedes combinar la copia de seguridad con otras tareas como enviar email, tareas de FTP, ejecutar procesos. Por ejemplo puedes recibir un email si la copia de seguridad falla o subirla a un <a href="ftp://ftp.and">FTP.</a> También puedes invocar archivos por lotes, llamar servicios web o ejecutar scripts C#. </p><br /><br /><p><img src="http://www.sqlservercentral.com/Images/15314.jpg" width="499" height="217" /></p><br /><br /><p><strong>Consejo 10. ADO.net</strong></p><br /><br /><p>Para Windows Forms y ASP.net es común utilizar ADO.net. ADO.net es utilizado en aplicaciones para insertar, eliminar o actualizar datos. Sin embargo puedes hacer una copia de seguridad de una base de datos utilizando ADO.net. el siguiente es un ejemplo de como realizar una copia de seguridad. </p><br /><br /><pre>//C# codigo para crear una copia de seguridad con ADO.net<br /> using System.Data.SqlClient;<br /><br /><br /> //Crear una conexión a la base de datos de prueba. </pre><br /><br /><pre>//Integrated security is Windows<br /> //Authentication<br /> string ConnectionString = @"Data Source=Localhost;" +<br /> "Initial Catalog=test;Integrated Security=True";<br /> SqlConnection cnn = new SqlConnection(ConnectionString);<br /><br /> //backup the database test in the c:\backup folder<br /> SqlCommand cmd = new SqlCommand(@"BACKUP DATABASE [test] TO "+<br /> @"DISK = N'C:\backup\test.bak'", cnn);<br /> cmd.CommandType = CommandType.Text;<br /><br /> cnn.Open();<br /> //Execute the command<br /><br /> cmd.ExecuteNonQuery();<br /><br /> Console.Write("Backup completed successfully");<br /><br /> cnn.Close();</pre><br /><br /><h5><strong>Consejo 11. SMO</strong></h5><br /><br /><p>SMO o SQL Management Objects es una gran opción utilizada por C# y Visual Basic. El siguiente ejemplo muestra como realizar una copia de seguridad utilizando VB: </p><br /><br /><p>Necesitas agregar los siguiente ensamblados:  </p><br /><br /><ul><br /> <li>Microsoft.SqlServer.ConnectionInfo.dll </li><br /><br /> <li>Microsoft.SqlServer.Smo.dll </li><br /><br /> <li>Microsoft.SqlServer.SmoEnum.dll </li><br /><br /> <li>Microsoft.SqlServer.SqlEnum.dll </li><br /><br /> <li>Microsoft.SqlServer.Management.Sdk.Sfc.dll  </li><br /></ul><br /><br /><p>Luego crear el código: </p><br /><br /><pre>Imports Microsoft.SqlServer.Management.Smo<br />Sub Main()<br /><br /> 'Enter the name of the database<br /> backupmethod("test")<br /><br /> End Sub<br /> 'Method to make the Backup<br /> Private Sub backupmethod(bd)<br /> Dim Myserver As Server = New Server("localhost")<br /> 'Create the instance of the class backup<br /> Dim backup As Backup = New Backup()<br /> 'Use windows authentication<br /> Myserver.ConnectionContext.LoginSecure = True<br /> Try<br /> 'Connect to the server<br /> Myserver.ConnectionContext.Connect()<br /> Console.WriteLine("*** Backing up ***")<br /> Dim path As String<br /> 'Set the path of the backup<br /> path = "C:\Testd.bak"<br /> backup.Devices.AddDevice(path, DeviceType.File)<br /> backup.Database = bd<br /><br /> 'select the type of backup action (you can also make backup <br />'copies of records and archives)<br /> backup.Action = BackupActionType.Database<br /> 'If the backup is not incremental set to false<br /> backup.Incremental = False<br /><br /> backup.Initialize = True<br /> backup.LogTruncation = BackupTruncateLogType.Truncate<br /> backup.SqlBackup(Myserver)<br /> Console.ReadKey()<br /> 'close the connection to server<br /> Myserver.ConnectionContext.Disconnect();<br /> Catch ex As Exception<br /> Console.WriteLine("Connection failed.")<br /> End Try<br /><br /> End Sub</pre><br /><br /><h4><strong>Conclusiones</strong></h4><br /><br /><p>Cuando trabajas con SQL Server necesitas conectar con otras aplicaciones utilizando métodos diferentes. El tutorial presente muestra algunas herramientas para crear copias de seguridad. Dependiendo de las circunstancias puedes necesitar un método diferente. </p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-5402805737572449532011-11-23T23:09:00.001-05:002011-11-24T08:59:46.810-05:00Conectar Visual Basic .NET a SQL Server 2008<p>Un amigo ha pedido explique como conectar Visual Basic .NET a una base de datos en SQL Server 2008 R2. Veamos como se hace.</p> <p>Primeramente tenemos que crear un proyecto en Visual Studio (tengo la versión 2008). Por defecto se crea el proyecto con un formulario. Hacemos doble click sobre el formulario para ver el panel del código.</p> <p>Escribimos la siguiente sentencia arriba de la definición de clase del formulario</p> <p align="center"><em>Imports System.Data.SqlClient</em></p> <p>Quedará como vemos en la imagen:</p> <p><a href="http://lh4.ggpht.com/-cFJA7tB3LRY/Ts3DXK0GFbI/AAAAAAAAWpA/W0e2nKn6Bhw/s1600-h/image%25255B49%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-5oaNq-rEm7Y/Ts3DabRd2EI/AAAAAAAAWpI/AxouODOU2AQ/image_thumb%25255B51%25255D.png?imgmax=800" width="600" height="165" /></a></p> <p>Luego estableceremos la conexión a la base de datos, para eso necesitamos dos datos: el nombre de la instancia del servidor SQL Server y el nombre de la base de datos. Con ellos creamos la cadena de conexión que nos permitirá conectarnos al servidor. Como ven, utilizamos la opción de conexión con seguridad integrada.</p> <p><a href="http://lh3.ggpht.com/-JLaqQSo6zO4/Ts3DblTPpxI/AAAAAAAAWpQ/cMDwNi_RlRQ/s1600-h/image%25255B64%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-Jhso6fjqMg8/Ts3DeIyHcSI/AAAAAAAAWpY/E7X8PEfLPaY/image_thumb%25255B69%25255D.png?imgmax=800" width="554" height="301" /></a></p> <p>Luego declaramos el objeto SqlConnection llamado CnxBD , que es el que hace el trabajo de establecer comunicación con el servidor y la base de datos. Y lo único que necesitamos es abrir la conexión con el método Open.</p> <p><a href="http://lh4.ggpht.com/-zzxXxGfJ-1k/Ts3DfgykGAI/AAAAAAAAWpg/mo0ppvhQkPY/s1600-h/image%25255B63%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-QEzeBjbnFQY/Ts3DhAuZLqI/AAAAAAAAWpo/i0m4Q--rvl4/image_thumb%25255B68%25255D.png?imgmax=800" width="577" height="217" /></a></p> <p>Con esa sentencia ya tendremos abierta una conexión a una base de datos de un servidor SQL Server.</p> <p>Esto es algo básico y como ven no tiene mucha complejidad, posterior a esto, ya podemos ir utilizando otros objetos como SqlCommand, Dataset, etc.</p> <p><a href="http://dl.dropbox.com/u/6564936/EjemplosVB/WACnxSqlServer.zip" target="_blank">Descargar código del ejemplo.</a></p> <p><em><strong><font color="#ff0000">Si tienes alguna duda o consulta, deja tu comentario. </font></strong></em></p> Unknownnoreply@blogger.com17tag:blogger.com,1999:blog-1855563562307870254.post-2799363943104612272011-11-23T09:45:00.001-05:002011-11-23T09:47:00.612-05:00Pantalla de Bienvenida con Windows Forms<p>En este artículo veremos como implementar una pantalla de bienvenida (splash screen) para nuestra aplicación. Lo haremos en Windows Forms (Visual Basic .NET 2008 / .NET Framework 3.5).</p> <p>Seguramente muchas veces has visto que las aplicaciones muestran una pantalla de bienvenida antes de mostrar la pantalla real.</p> <p>Aquí utilizaremos varias imágenes en una especie de carrusel, es decir una serie de imágenes apareciendo una tras otra en la pantalla de bienvenida automáticamente.</p> <p>Para empezar hay que crear una aplicación Windows Forms llamada PantallaSplash.</p> <p>Al formulario que se agrega automáticamente, hay que incorporar tres componentes: un ImageList (con el nombre imgPics), un Timer (tmrSplash) y un PictureBox (picBox) de la caja de herramientas. </p> <p>En el control ImageList imgPics almacenaremos una o más imágenes. La configuración debe estar como la siguiente.</p> <p><a href="http://lh4.ggpht.com/-wU6SQBEAPtg/Ts0GwrqcFhI/AAAAAAAAWoA/rL5Qz7ejy_0/s1600-h/image%25255B3%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-yULl0o7If1M/Ts0GyDFyL_I/AAAAAAAAWoI/VZfzJCI_S7s/image_thumb%25255B6%25255D.png?imgmax=800" width="244" height="204" /></a></p> <p>Con el control Timer controlaremos un intervalo de tiempo en que un evento se ejecute. Configura el timer como se ve en la siguiente imagen.</p> <p><a href="http://lh6.ggpht.com/-U8iW41cN6H0/Ts0GzUeLPwI/AAAAAAAAWoQ/-ZSF9BsOfQs/s1600-h/image%25255B7%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/--Ad6qCTHwsk/Ts0G089vxkI/AAAAAAAAWoY/sDKRmkENETA/image_thumb%25255B12%25255D.png?imgmax=800" width="244" height="165" /></a></p> <p>Y en el control PictureBox mostraremos una imagen. Configúralo de la siguiente manera (tienes que establecer una de las imágenes que pusimos en el control ImageList):</p> <p><a href="http://lh6.ggpht.com/-CemlfHNJCMU/Ts0G2Og4HPI/AAAAAAAAWog/aE5bfTQBiJw/s1600-h/image%25255B11%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-3GonCy15D1s/Ts0G3k6J8_I/AAAAAAAAWoo/dWGLcD4YX1o/image_thumb%25255B18%25255D.png?imgmax=800" width="186" height="244" /></a></p> <p>Asegúrate que el tamaño del control PictureBox tenga el mismo tamaño que se coloco en la propiedad ImageSize del control ImageList.</p> <p>Escribamos el siguiente código que es el que hará el trabajo.</p> <p><a href="http://lh3.ggpht.com/-k-UPyJ3gF6s/Ts0G5Mv9HTI/AAAAAAAAWow/iQDTWKLl3To/s1600-h/image%25255B64%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-mh8roV_EKc8/Ts0G8C9O68I/AAAAAAAAWo4/lpaIHKd_tHE/image_thumb%25255B74%25255D.png?imgmax=800" width="604" height="396" /></a></p> <p>En el evento Load del formulario habilitamos el timer. Con la variable “index” vamos recorriendo la lista de imágenes y mostrándolas en el control PictureBox.</p> <p>A continuación dejo el enlace para que puedan descargar el código (incluyo las imágenes que utilicé).</p> <p><a href="http://dl.dropbox.com/u/6564936/EjemplosVB/PantallaSplash.zip" target="_blank">PantallaBienvenida.zip</a></p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-40966718787743784782011-11-19T10:34:00.001-05:002011-11-19T10:34:22.865-05:00Como Reducir el Tamaño del Log de Transacciones en SQL Server<p>Una pregunta muy común es cómo reducir el tamaño del log de transacciones en SQL Server 2008 o en versiones superiores, porque son instrucciones diferentes que las utilizadas para SQL Server 2000 o SQL Server 2005 .</p> <p><strong><em>Reducir el Log de Transacciones en SQL Server 2008</em></strong></p> <p>En este caso usaremos la base de datos <i>AdventureWorks</i>:</p> <p><code>USE AdventureWorks</code></p> <p><code>GO</code></p> <p><code>ALTER</code> <code>DATABASE</code> <code>AdventureWorks </code></p> <p><code>SET</code> <code>RECOVERY SIMPLE</code></p> <p><code>GO</code></p> <p><code>DBCC SHRINKFILE (AdventureWorks_Log)</code></p> <p><code>GO</code></p> <p><code>ALTER</code> <code>DATABASE</code> <code>AdventureWorks </code></p> <p><code>SET</code> <code>RECOVERY </code><code>FULL</code></p> <p><code>GO</code></p> <p>Recuerda que en este ejemplo la instrucción <a href="http://technet.microsoft.com/es-es/library/ms189493.aspx">DBCC SHRINKFILE</a> reduce el fichero de log al máximo (en el parámetro se le debe indicar el nombre lógico del fichero).</p> <p><strong><em>Reducir el Log de Transacciones en SQL Server 2000/2005</em></strong></p> <p>Primero ejecuta el siguiente código:</p> <div><code> <div align="center"> <pre>DBCC SHRINKFILE(pubs_log, 2)</pre><br /> </div><br /><br /> <p><font face="Georgia">Si no se obtiene el tamaño deseado, ejecute lo siguiente:</font></p><br /><br /> <div><code><br /> <div align="center"><br /> <pre>BACKUP LOG pubs WITH TRUNCATE_ONLY</pre><br /> </div><br /><br /> <pre><font face="Georgia">Eso trunca el registro, sin posibilidad a una copia de seguridad.</font></pre><br /><br /> <pre><font face="Georgia"></font></pre><br /> </code></div><br /> </code></div> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-85382815389101487702011-11-12T17:35:00.001-05:002011-11-12T17:35:47.816-05:0010 Ideas Asesinas en el Desarrollo de Software<p>Los ingeniero de software son siempre curiosos, entusiastas y animados a hacer todas las cosas. Al menos al principio. En el camino, estos cabezotas se enfrentan con un mundo que definitivamente no entiende sobre el desarrollo de software, sistemas que cuentan ingenieros por números, productividad por líneas de código y calidad de procesos; un mundo donde el desarrollo de software está manejado por una burocracia que maneja riesgos más que un consejo creativo que pueda resolver los problemas de los clientes.</p> <p>Desafortunadamente, muchos ingenieros consideran esto una llamada para despertar y adoptar esas formas burocráticas, convencidos que han aterrizado en un nuevo y adulto mundo de la administración. Alguien que administre resistir a dar un mal paso y no caiga en las tentaciones del martirio, ya que cada fallo es algo que la administración hizo o no hizo.</p> <p>Si eres un ingeniero de software o un jefe de ingenieros, a continuación tenemos una lista para ayudarte a identificar si sigues con tus genes de desarrollo de software activos o te has convertido en alguien que dicta clichés de forma robótica en cada reunión, asesinando cada idea y la moral detrás de ella:</p> <p>10. "<strong>Esto es suficientemente bueno</strong>" : El hecho es que nada es suficientemente bueno, al menos para cualquier software. Puede ser suficientemente bueno para hoy, o para esta versión, pero si tu producto ha tenido el mismo problema la última década, alguna empresa de la competencia ya se ha llevado a tus clientes por ello. Repáralo antes que llegues al punto donde no puedas.</p> <p>9. "<strong>Esta es la forma en que siempre lo hemos hecho</strong>": Esto es un anacronismo en cualquier campo competitivo y rápidamente cambiante. Especialmente en el software. Las empresas de software no son como empresas fabricantes de autos que pueden ensamblar cualquier línea y olvidarse de ella por unos cien años. ¡Espera un minuto! Ni siquiera las empresas fabricantes de autos hacen eso. Los problemas de hoy requieren un nuevo conjunto de soluciones porque en una industria que funciona bajo algo como las Leyes de Moore, junto con las expectativas de las personas, hay un estado permanente de cambio.</p> <p>8. "<strong>Hay suficiente tiempo para hacerlo bien</strong>": Esto es la forma en que acabas en <a href="http://es.wikipedia.org/wiki/Deuda_t%C3%A9cnica" rel="nofollow" target="_blank">deuda técnica</a>. De alguna forma es inevitable debido a las presiones del negocio o trabajar con una nueva pieza de hardware o tecnología. Tanto como vas pagando tu deuda en el futuro inmediato, esto es parte del proceso, pero si evitas hacer las decisiones correctas y la responsabilidad va con eso, no vas a ser consecuente con tus principios de ingeniero de software.</p> <p>7. "<strong>Esto requiere cambios arquitecturales profundos</strong>": ¿Qué cosa no las necesita? Idealmente, una pieza bien diseñada de software debería ser flexible a los cambios mientras el producto se va desarrollando. Pero como nosotros dijimos, la demanda en el software cambia rápidamente y cada pieza de software escrita necesita ser volver a ser escrita. Esta es la naturaleza del trabajo, no una anomalía para ser utilizada como una excusa.</p> <p>6. "<strong>La Administración no lo ha priorizado</strong>": ¿Acaso la administración no ha priorizado hacer un buen producto? ¿libre de errores? ¿sin código mal escrito? ¿que hace al cliente feliz? De acuerdo, algunas veces heredamos código y tendremos que lidiar entre reparar lo que ya está hecho y escribir nuevo código pero ese es un argumento poco válido como veremos a continuación. Es suficiente decir que la ingeniería necesita configurar y ejecutar sus propias prioridades, aunque sean pequeñas, cada día, en vez de esperar por algún mandato superior y mágico, <strong>ya que eso no va a suceder</strong>.</p> <p>5. "<strong>Hay mucho en nuestro plato</strong>": Esta es una de las tautologías sin sentido que no añade nada a la discusión. El foco no es más la idea o como debería ser ejecutada sino “no tenemos recursos” o la enorme lista de errores presentada por el cliente. Por supuesto que tienes mucho en tu plato, ya que te pagan por tener eso en tu plato, <strong>empieza a comer</strong>.</p> <p>Si una idea vale ser ejecutada, su adopción no debería depender si tienes o no mucho en tu plato, si llenas tu plato en el buffet con basura y decides que no tienes el plato deseado porque tu plato está lleno, ya has hecho dos cosas mal: elegiste malas cosas para empezar y no tienes que hacer muchos cálculos para saber que tienes que tirar la basura y conseguir lo que quieres. No mates la idea, limpia el plato.</p> <p>4. "<strong>Nuestro software es muy completo, tenemos que tener cuidado si hacemos cambios</strong>": Esta es otra tautología sin sentido. ¿Qué software empresarial no es complejo? ¿Estás diciendo que no eres usualmente poco cuidadoso cuando escribes código? Eres un ingeniero de software, y debes esperar lidiar con la complejidad y ser cuidadoso cuando haces cambios, es un requerimiento básico. Si esta fuera una razón por la que los ingenieros no pueden ejecutar una idea, deberíamos aprender nuevamente lo básico.</p> <p>3. "<strong>Nadie está pidiendo eso</strong>": Esto puede hacer recordar a un comentario que hizo Henry Ford: “si le preguntara a la gente, lo que ellos quieren, ellos dirán que quieren un caballo más rápido”. Los seres humanos son increíblemente adaptables, ellos vivirían con cualquier cosa, incluyendo como dijo Ford, caballos más rápidos. Si le das a tus clientes un producto por debajo de los estándares, ellos vivirán con eso. Pero recuerda que los humanos también somos increíblemente cambiantes, una idea que mates o que tengas encerrada, crecerá en otra empresa. Si somos descuidados porque creemos que nuestro software es “pegajoso” (es decir que los clientes nos odian pero no pueden cambiar porque es mucho trabajo), estamos fijando nuestro techo en un nivel que no vale para un verdadero ingeniero.</p> <p>2. "<strong>Tenemos consensos</strong>": Esto parecería una afirmación inocua con noble intención, pero es insidiosa y fijándonos bien, no tienen ningún significado en el contexto del software. El consenso tiene una indebida importancia en todo desde reuniones de diseño, revisiones de SRS/SDS, documentación, prácticas de QA, etc. El desarrollo de software es un ejercicio de conducción por expertos. Alguien que ha pasado años estudiando, aprendiendo y trabajando en un campo específico, y no apartas a esa persona para la decisión final arrojando toda esa experiencia, sin mencionar que puedes entregar un mal producto, desmoralizar al experto, y adoptar la forma más segura y más tímida y más insidiosa de todas, la contabilidad difusa.</p> <p>Una decisión de grupo es una forma de evadir la responsabilidad por el producto. “Lo decidimos todos”, es una forma de decir: “nadie es responsable”. En un sistema presidencial de gobierno, el congreso recomienda al presidente pero el presidente es el que toma la decisión. A menos que la decisión del presidente sean obviamente horrenda que la mayoría del congreso decida vetar la decisión, esta queda. </p> <p>1. "<strong>No puede ser hecho</strong>": No hay nada que no pueda ser hecho en software. Los chicos no ingenieros te rodean diciendo “es solo software, cierto” como una forma gentil de provocar a los ingenieros ¡pero es verdad! Es esencialmente solo software. Los ingenieros debería responder especificando lo que toma implementar más que decir que no puede ser hecho. Deberíamos decir “tomará 3 ingenieros, con licencias para XYZ, cinco computadoras con el procesador DFE, con 2 TB de almacenamiento, y 8 meses para hacer ese software”, en vez de “no puede hacerse”.</p> <p><em>Todo </em>puede ser hecho, fijemos eso en nuestra mente primero. El resto caerá por su propio peso.</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-16768420700895307622011-07-17T23:01:00.000-05:002011-07-17T23:01:03.729-05:00Información de Tablas [Script SQL]<p>Este script puede ser utilizado para obtener la información de tablas.</p> <table border="0" cellspacing="0" cellpadding="2" width="500"><tbody> <tr> <td valign="top" width="500"><font face="Verdana"></font></td> </tr> <tr> <td valign="top" width="500"> <p><font face="Verdana">SELECT TAB.NAME AS NOMBRE_TABLA, COL.NAME AS NOMBRE_COLUMNA, </font><font face="Verdana">TIP.NAME AS TIPO_DATO, </font><font face="Verdana">COL.MAX_LENGTH AS TAMAO, </font></p> <p><font face="Verdana">CASE <br />    WHEN COL.IS_NULLABLE = '0' THEN 'NO'</font></p> <p><font face="Verdana">    ELSE 'SI'</font></p> <p><font face="Verdana">END AS ACEPTA_NULL,</font></p> <p><font face="Verdana">EXT.VALUE AS DESCRIPCION <br />     <br />FROM SYS.TABLES TAB</font></p> <p><font face="Verdana">INNER JOIN</font></p> <p><font face="Verdana">SYS.COLUMNS COL ON TAB.OBJECT_ID = COL.OBJECT_ID</font></p> <p><font face="Verdana">INNER JOIN</font></p> <p><font face="Verdana">SYS.TYPES TIP ON TIP.USER_TYPE_ID = COL.USER_TYPE_ID</font></p> <p><font face="Verdana">LEFT OUTER JOIN</font></p> <p><font face="Verdana">SYS.EXTENDED_PROPERTIES EXT ON EXT.MAJOR_ID = TAB.OBJECT_ID AND COL.COLUMN_ID = EXT.MINOR_ID</font></p> </td> </tr> <tr> <td valign="top" width="500"><font face="Verdana"></font></td> </tr> </tbody></table> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-18041593546017346472011-07-15T18:25:00.000-05:002011-07-15T18:25:00.170-05:00Reemplazando Cursores con Consultas SQL<p>Para poner las cosas en claro, creo que así como yo, casi todos prefieren evitar los cursores en la mayoría de los casos. ¿Son necesariamente malos? ¿Es una regla absoluta el evitar a un cursor? No. Algunas veces la operación que se necesita no puede ser hecha en base a conjuntos de datos, y un cursor puede ser desarrollado más rápido que un programa. Algunas veces es conocido que el avance en el bucle sólo involucra cientos de registros y no tomará mucho tiempo ejecutarse. Algunas veces estás trabajando con cursores ya existentes y sólo necesitas unos cambios menores, modificando el cursor en este escenario será más rápido que reescribir el procedimiento desde cero. Pero en general, yo intento evitar cursores mientras sea posible, y siempre busco alternativas para codificar la lógica.</p> <p>Es posible remover a esos feos cursores de la lógica de datos, en algunos casos es más complicado. Vamos a ver un ejemplo de un cursor que tal vez deberíamos reemplazar. Por ejemplo un cursor utilizado para extraer información de estudiantes y que actualice la elección de transporte, un estudiante a la vez. La lógica es la siguiente:</p> <p>1. Recuperar el nivel de grado del estudiante (inicial, primaria, o secundaria) en una variable.</p> <p>2. Limpiar el código de transporte si el estudiante está dentro de la distancia adecuada para caminar a la escuela (la distancia es determinada en base también al nivel del estudiante).</p> <p>3. Si el estudiante no está en una categoría particular (educación especial por ejemplo) y no está en un conjunto particular de colegios, establece el código de transporte a inelegible si los estudiantes están fuera de la zona.</p> <p>4. Si el estudiante está en un programa de mediodía, actualizar el código de transporte para resaltar el hecho que el transporte será por mediodía.</p> <p>5. Actualizar el código de transporte si el estudiante no reúne ninguno de los otros criterios.</p> <p>La lógica utilizada en el cursor sería una enredada telaraña de sentencias de actualización, anidadas en una lógica muy compleja. Para hacerlo peor, digamos que hay 60 mil estudiantes, y esto podría tomar algo de 20 minutos para ejecutarse.</p> <p><strong>El Cursor</strong></p> <p>Veamos ahora como podría ser el cursor a utilizar para la operación que explicamos anteriormente.</p> <table border="0" cellspacing="0" cellpadding="2" width="500"><tbody> <tr> <td valign="top" width="500"> </td> </tr> <tr> <td valign="top" width="500"> <pre><font face="Arial">DECLARE EstudiantesCursor CURSOR FAST_FORWARD FOR<br /> SELECT <br /> NumeroEstudiante,<br /> CodigoEscuela,<br /> CodigoTransporte,<br /> NivelGrado,<br /> CodigoGeografico,<br /> ZonaHogar,<br /> CodigoBilingual,<br /> CodigoSped<br /> FROM <br /> -- [Tablas para obtener la información de estudiantes]   OPEN EstudiantesCursor   FETCH NEXT FROM EstudiantesCursor INTO <br /> @</font><font face="Arial">NumeroEstudiante</font><font face="Arial">,<br /> @</font><font face="Arial">CodigoEscuela</font><font face="Arial">,<br /> @</font><font face="Arial">CodigoTransporte</font><font face="Arial">,<br /> @</font><font face="Arial">NivelGrado,</font><font face="Arial"><br /> @</font><font face="Arial">CodigoGeografico</font><font face="Arial">,<br /> @</font><font face="Arial">ZonaHogar</font><font face="Arial">,<br /> @</font><font face="Arial">CodigoBilingual</font><font face="Arial">,<br /> @</font><font face="Arial">CodigoSped</font></pre><br /><br /> <pre><font face="Arial">WHILE @@FETCH_STATUS = 0<br />BEGIN<br /> -- Para el nivel de grado, ver si el estudiante es inelegible</font></pre><br /><br /> <pre><font face="Arial"> -- para transporte (vive muy cerca de la escuela).<br /> IF EXISTS(SELECT Sch FROM DistanciaCaminando<br /> WHERE CodigoEsc = @CodigoEscuela<br /> AND CodigoGeo = @CodigoGeografico</font></pre><br /><br /> <pre><font face="Arial"> AND NivelGrado = @NivelGrado)<br /> BEGIN<br /> UPDATE <br /> Registro<br /> SET<br /> CodigoTransporte = '', <br /> LastUpdateUserID= 'CScrpW' -- inelegible<br /> WHERE <br /> NumeroEstudiante = @</font><font face="Arial">NumeroEstudiante</font></pre><br /><br /> <pre><font face="Arial"><br /> AND CodigoEsc = @CodigoEscuela  GOTO FetchNext<br /> END     IF ((rtrim(@CodigoBilingual) = '' <br /> OR RTRIM(isnull(@</font><font face="Arial">CodigoBilingual</font><font face="Arial">,'')) = 'S')<br /> AND (@CodigoSped = '' <br /> OR SUBSTRING(@CodigoSped, 1, 1) IN ('S', 'R') <br /> OR @CodigoSped IN ('V1', 'V2', 'P1', 'P2'))) <br /> BEGIN<br /> IF @NivelGrado <> 'H' <br /> AND NOT EXISTS<br /> (SELECT Escuela FROM BufferZoneLookup <br /> WHERE Escuela = @Escuela <br /> AND </font><font face="Arial">NivelGrado = @</font><font face="Arial">NivelGrado </font><font face="Arial"><br /> AND (CodigoGeo = @CodigoGeografico<br /> OR ZonaHogar IN (@ZonaHogar, 'C','H')))<br /> BEGIN<br /> -- codigo aqui para ejecutar una actualizacion pero</font></pre><br /><br /> <pre><font face="Arial">--indicando el codigo de transporte a 'C0RR' y el UltimoUsuario a 'CScrpZ'<br /> END   GOTO FetchNext<br /> END   -- Dos actualizaciones adicionales con condicionales</font></pre><br /><br /> <pre><font face="Arial"><br /> FetchNext:<br /> FETCH NEXT FROM EstudiantesCursorINTO <br /></font><font face="Arial"> @</font><font face="Arial">NumeroEstudiante</font><font face="Arial">,<br /> @</font><font face="Arial">CodigoEscuela</font><font face="Arial">,<br /> @</font><font face="Arial">CodigoTransporte</font><font face="Arial">,<br /> @</font><font face="Arial">NivelGrado,</font><font face="Arial"><br /> @</font><font face="Arial">CodigoGeografico</font><font face="Arial">,<br /> @</font><font face="Arial">ZonaHogar</font><font face="Arial">,<br /> @</font><font face="Arial">CodigoBilingual</font><font face="Arial">,<br /> @</font><font face="Arial">CodigoSped</font></pre><br /><br /> <pre><font face="Arial"> END<br />END<br />CLOSE EstudiantesCursor<br />DEALLOCATE EstudiantesCursor</font></pre><br /> </td><br /> </tr><br /><br /> <tr><br /> <td valign="top" width="500"><font face="Arial"></font></td><br /> </tr><br /> </tbody></table><br /><br /><p>Lo siguiente que hay que hacer para reemplazar el cursor con una sentencia SQL de conjuntos de datos es identificar las condiciones y bucles a repetir.</p><br /><br /><p>1. Encapsular las condiciones if/else que hay en el cursor en una tabla temporal con múltiples columnas tipo BIT. Para estas, mas de una de las condiciones pueden ser establecidas.</p><br /><br /><p>2. Utilizar la tabla temporal con las configuraciones tipo bit para determinar el código de transporte. Las sentencias de actualización simplemente modifican el código de transporte ý la última actualización al usuario, de modo que eso se realiza en una tabla temporal secundaria. En la lógica, el orden de las sentencias case realiza las actualizaciones en el cursor.</p><br /><br /><p>3. Utilizar los códigos de transporte que tenemos en la tabla 2 para realmente hacer las actualizaciones.</p><br /><br /><p>A continuación el SQL resultante:</p><br /><br /><table border="0" cellspacing="0" cellpadding="2" width="500"><tbody><br /> <tr><br /> <td valign="top" width="500"> </td><br /> </tr><br /><br /> <tr><br /> <td valign="top" width="500"><br /> <pre><font face="Arial">-- Esta consulta llenará una tabla con diferentes campos tipo bit <br />-- representando las condiciones if/else utilizadas en el cursor. <br />-- de modo que esto esencialmente centraliza las condiciones if/else en un <br />-- registro por cada estudiante que pueda ser usada para la siguiente consulta.<br />SELECT<br /> ds.NumeroEstudiante,<br /> ds.CodigoEscuel,<br /> ds.CodiogTransporte,<br /> ds.NivelGrado,<br /> ds.CodigoBilingual,<br /> ds.CodigoSped,<br /> ds.CodigoGeografico,<br /> ds.ZonaHogar,<br /> (CASE WHEN ds.sch IN('4261','1010','1020','1340')<br /> THEN 1 ELSE 0 END) AS 'NoPuedeEstarFueraDeZona', </font></pre><br /><br /> <pre><font face="Arial">– distancia ciudad<br /> (CASE WHEN isnull(ZonaEsc.esc, '') <> '' THEN 1 ELSE 0 END) <br /> AS 'EnZonaOZonaBuffer',<br /> (CASE WHEN isnull(DistanciaCaminando.es, '') <> '' THEN 1 ELSE 0 END)<br /> AS 'EstaEnLaDistanciaCamino',<br /> (CASE WHEN ds.grado IN ('K0', 'K1') <br /> AND ds.esdiaextendido = 0 THEN 1 ELSE 0 END) <br /> AS 'InicialMedioDia',<br /> -- Bilingual estudiantes de otro idioma que siempre necesitan transporte.<br /> (CASE WHEN NOT isnull(ds.CodigoBilingual, '') = '' <br /> AND NOT (isnull(ds.CodigoBilingual,'')) = 'S' THEN 1 ELSE 0 END)<br /> AS 'BilingualInelegibleParaC0RR',<br /> -- casos adicionales omitidos</font></pre><br /><br /> <pre><font face="Arial"> [SpedInelegibleParaC0RR]<br />INTO #EstudiantesProcesar</font></pre><br /><br /> <pre><font face="Arial">FROM</font></pre><br /><br /> <pre><font face="Arial">—[lista de tablas] similar a las que están en la definición del cursor</font></pre><br /><br /> <pre><font face="Arial">—usa los campos tipo bit para indicar el tipo de codigo de transporte</font></pre><br /><br /> <pre><font face="Arial">SELECT ds.numeroEstudiante, ds.codigoTransporte AS 'curTransCodigo',<br /> -- en el rango idnicado<br /> (CASE WHEN </font><font face="Arial">EstaEnLaDistanciaCamino</font><font face="Arial">= 1 THEN ''<br /> -- indica fuera de zona, secundaria y otras categorias no pueden estar </font></pre><br /><br /> <pre><font face="Arial">--fuera de zona</font></pre><br /><br /> <pre><font face="Arial"> WHEN BilingualInelegibleForC0RR = 0<br /> AND NOT sys.grado IN('09','10','11','12') <br /> AND EnZonaOZonaBuffer = 0 <br /> AND NoPuedeEstarFueraZona = 0 THEN 'C0RR'<br /> WHEN (EsInicialMedioDia = 1 <br /> AND isnull(sys.transcode, '') = '') THEN 'C5*R'<br /> WHEN (EsInicialMedioDia = 1 <br /> AND isnull(sys.codigotransporte, '') <> '') THEN sys.codigotransporte<br /> ELSE 'C5RR' END) AS 'CodigoPropuestoTransporte'<br />INTO #CambiosTransportecodigoPropuesto<br />FROM <br /> -- [lista de tablas]  </font></pre><br /><br /> <pre><font face="Arial">--ejecuta la actualizacion, indica los codigos de elegibilidad de transporte </font></pre><br /><br /> <pre><font face="Arial">--[c5rr, c0rr, etc]. <br />-- cada actualización usa un ID diferente<br />UPDATE ds SET codigotransporte = </font><font face="Arial">CodigoPropuestoTransporte,</font><font face="Arial"><br />ultimoUsuario = (CASE isnull(CodigoPropuestoTransporte, '') <br /> WHEN 'c5rr' THEN 'CScrpC'<br /> WHEN 'c0rr' THEN 'CScrpZ' <br /> WHEN '' THEN 'CScrpW' <br /> WHEN 'C5*R' THEN 'CScrpK' <br /> ELSE 'CScrpX' END)<br />FROM <br /> -- [lista de tablas]</font></pre><br /> </td><br /> </tr><br /><br /> <tr><br /> <td valign="top" width="500"> </td><br /> </tr><br /> </tbody></table><br /><br /><p>Esta consulta se ejecutará 10 o 100 veces más rápido que el cursor. ¿Porqué es tan lento el cursor? Porque cada estudiante es procesado uno a la vez. Y para empeorar las cosas, dentro de cada bucle del cursor, hay algo de cinco consultas a la vez, lo que si contamos con 60 mil estudiantes, serían algo de 300 mil consultas. Y sólo se necesitaban 3. Pero, y siempre hay un pero en la vida, la opción de usar un cursor mejora la depuración y lo hace más flexible que la opción de consultas. Siempre hay que decidir que es lo que queremos obtener: velocidad o simplicidad.</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-13070736347426688272011-07-14T18:24:00.001-05:002011-07-14T18:24:15.654-05:00¿Dónde Poner la Lógica? ¿En SQL o en el código?<p>SQL es un poderoso lenguaje de programación y es muy bueno para lo que fue hecho, consultas de conjuntos de datos. C#, Java y otros lenguajes son también poderosos, más poderosos que SQL en muchas formas. Para bucles y tareas en forma de procedimientos, C# puede procesar cientos de registros muchas veces más rápido que un cursor SQL, e incluso hacerlo en unas líneas de código más escasas. SQL simplemente no fue hecho para hacer ese tipo de procesamiento. En vez de eso, SQL fue hecho para procesar conjuntos de datos donde las tablas y conjuntos de resultados son utilizados y combinados en base a condiciones. </p> <p>De manera similar, SQL es de lejos la interfaz de usuario que uno quiere tener. Muchas tareas que necesitan una interfaz de usuario, no son apropiadas para la lógica SQL. Por ejemplo, si los nombres de clientes deberían aparecer en una rejilla web con el formato [nombres],[apellido paterno][apellido materno], una opción es retornar los datos desde una sentencia SQL con ese formato. Sin embargo, un método más apropiado es simplemente retornar las partes del nombre, y que la lógica en la interfaz de usuario formatee el nombre completo en el formato deseado.</p> <p>Algunos puntos para tomar en cuenta:</p> <p>1. ¿Qué pasa si la capa de negocios o la interfaz de usuario está bloqueada y la única forma de cambiar el formato es cambiar los datos que se carga?</p> <p>2. ¿Qué pasa si en vez de que los datos sean llamados por una aplicación o sólo un sitio web, sean llamados por 2 o 3 aplicaciones web, y estén disponibles como un servicio web, y de paso por una aplicación de consola? Mientras que en teoría un componente de negocios puede ser desarrollado para manejar todas esas llamadas, una opción más fácil es simplemente centralizar a nivel de base de datos en un procedimiento almacenado la salida de datos.</p> <p>3. ¿Qué pasa si los resultados necesitan ser llamados por otra pieza de lógica SQL? Podría ser transformados en una vista.</p> <p>4. ¿Qué pasaría si el resultado está destinado a mostrarse como un archivo de Excel que será rápidamente modificado ya que el usuario pide un reporte personalizado? ¿Qué pasa si ellos solicitan otra vez una pequeña modificación de la lógica unos cuantos minutos después que finalices de modificar el formato del archivo de Excel? ¿No podría ser más fácil tener la lógica en el SQL en este caso?</p> <p>5. ¿Qué sucede si el desarrollador que escribió la lógica es simplemente más adepto a una solución basada en SQL para lo que se necesita?</p> <p>Para mi, si algo puede ser hecho en forma de conjuntos de datos, trato de hacerlo en SQL para terminar el trabajo, en todo lo que sea posible que pueda ser hecho en forma de conjuntos de datos, vayamos a la lógica SQL (y todo lo que requiera lógica de procedimientos va en el código).</p> <p>¿Que dices tú?</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-86925923219542361292010-06-02T09:51:00.012-05:002010-06-02T09:51:00.662-05:00Script Para Restaurar Base de Datos Desde Unidad O Carpeta de RedCuando utilizamos la interfaz de Sql Server, parece ser que es imposible restaurar una base de datos si es que no está en el disco duro local. Pero eso no es cierto, el problema es que sólo puede hacerse con un script como el siguiente:<br />
<br />
<div align="center" style="background-color: #fff7ef; text-align: left; width: 450px;"><b>RESTORE DATABASE </b><br />
DatabaseNameHere <br />
<b>FROM </b><br />
<b>DISK</b>='\\server_name\folder\filename.bak' <br />
<b>WITH REPLACE</b></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-4395060299983909702010-06-01T09:37:00.000-05:002010-06-01T09:37:35.087-05:00Script para Ver Historial de Trabajos con Timeline (línea de tiempo)Este script puede servir para chequear si hay dos o más trabajos en Sql Server, que sean concurrentes, proporcionando una forma visual.<br />
<br />
<div style="background-color: #fff7ef;">SET DATEFORMAT dmy<br />
SELECT <br />
convert(varchar(10),his.server) as Server,<br />
convert(varchar(30),job.name) AS job_name, <br />
CASE his.run_status<br />
WHEN 0 THEN 'Failed'<br />
WHEN 1 THEN 'Succeeded'<br />
ELSE '???'<br />
END as run_status,<br />
convert(varchar(4),run_duration/10000) + ':' + convert(varchar(4),run_duration/100%100) + ':' + convert(varchar(4),run_duration%100) as run_duration,<br />
convert(datetime, convert(varchar(10),run_date%100) + '/' + convert(varchar(10),run_date/100%100) + '/' + convert(varchar(10),run_date/10000) + ' ' + convert(varchar(4),run_time/10000) + ':' + convert(varchar(4),run_time/100%100) + ':' + convert(varchar(4),run_time%100)) as start_date,<br />
datediff(mi, getdate()-1, convert(datetime, convert(varchar(10),run_date%100) + '/' + convert(varchar(10),run_date/100%100) + '/' + convert(varchar(10),run_date/10000) + ' ' + convert(varchar(4),run_time/10000) + ':' + convert(varchar(4),run_time/100%100) + ':' + convert(varchar(4),run_time%100))) as LeadingMinutes,<br />
isnull(nullif(convert(int,(run_duration/10000 * 60) + (run_duration/100%100) + (ceiling(run_duration%100/60.0))),0),1) as DurationMinutes,<br />
REPLICATE(' ', datediff(mi, getdate()-1, convert(datetime, convert(varchar(10),run_date%100) + '/' + convert(varchar(10),run_date/100%100) + '/' + convert(varchar(10),run_date/10000) + ' ' + convert(varchar(4),run_time/10000) + ':' + convert(varchar(4),run_time/100%100) + ':' + convert(varchar(4),run_time%100)))) +<br />
REPLICATE('x', isnull(nullif(convert(int,(run_duration/10000 * 60) + (run_duration/100%100) + (ceiling(run_duration%100/60.0))),0),1)) as DurationTimeline,<br />
his.message<br />
FROM<br />
msdb.dbo.sysjobhistory his<br />
INNER JOIN msdb.dbo.sysjobs job ON his.job_id = job.job_id<br />
WHERE<br />
convert(datetime, convert(varchar(10),run_date%100) + '/' + convert(varchar(10),run_date/100%100) + '/' + convert(varchar(10),run_date/10000) + ' ' + convert(varchar(4),run_time/10000) + ':' + convert(varchar(4),run_time/100%100) + ':' + convert(varchar(4),run_time%100)) between getdate()-1 and getdate()<br />
and step_id = 0<br />
ORDER BY<br />
his.server,<br />
his.run_date,<br />
his.run_time,<br />
job.name</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-82693371540685150012009-09-27T16:44:00.000-05:002009-09-27T16:44:56.338-05:00Como Crear un App.Config para una Aplicacion .NET Compact FrameworkLa actual versión del .NET Compact Framework (viene con Visual Studio .NET 2003) no ofrece la capacidad de acceder a un archivo de configuración App.Config como lo hace una aplicación .NET Windows Form.<br />
<br />
Si deseas obtener la misma funcionalidad, simplemente carga el archivo de configuración en un XmlDocument y transforma el documento xml en una NameValueCollection. A partir de eso, puedes referenciar la colección AppSettings para recuperar el valor por el nombre de clave.<br />
<br />
Revisemos el siguiente ejemplo.<br />
<br />
Es importante anotar que necesitarás incluir el archivo App.Config en tu proyecto y configurar las propiedades del archivo para ser considerado Content (contenido).<br />
<br />
Esto asegura que tu archivo sea incluido con la distribución. <br />
<b><br />
</b><br />
<b>App.Config de muestra</b><br />
<br />
<pre class="PreSourceCode"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Item1" value="value of item 1" />
<add key="Item2" value="value of item 2" />
<add key="Item3" value="value of item 3" />
</appSettings>
</configuration>
</pre><br />
<b>Codigo de ejemplo (C#)</b><br />
<br />
using System;<br />
using System.Collections.Specialized; <br />
using System.Xml;<br />
using System.IO;<br />
<br />
public class ConfigurationSettings<br />
{<br />
<br />
public static NameValueCollection AppSettings;<br />
<br />
public static void LoadConfig()<br />
{ <br />
try<br />
{<br />
<br />
string AppPath = Path.GetDirectoryName( Assembly.GetExecutingAssembly().GetName().CodeBase);<br />
string ConfigFile = Path.Combine(AppPath,"App.config");<br />
<br />
if(File.Exists(ConfigFile) == false)<br />
{<br />
System.Windows.Forms.MessageBox.Show("Config file does not exist");<br />
Application.Exit(); <br />
return;<br />
}<br />
<br />
XmlDocument oXml = new XmlDocument();<br />
<br />
oXml.Load(ConfigFile);<br />
<br />
XmlNodeList oList = oXml.GetElementsByTagName("appSettings"); <br />
<br />
AppSettings = new NameValueCollection();<br />
<br />
foreach(XmlNode oNode in oList)<br />
{<br />
foreach(XmlNode oKey in oNode.ChildNodes)<br />
{<br />
AppSettings.Add(oKey.Attributes["key"].Value, oKey.Attributes["value"].Value);<br />
}<br />
}<br />
<br />
System.Windows.Forms.MessageBox.Show(ConfigurationSettings.AppSettings["Item1"]); <br />
<br />
}<br />
catch (Exception) { throw; }<br />
}<br />
<br />
}Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1855563562307870254.post-27194771141473227782009-09-09T11:49:00.001-05:002009-09-09T11:50:03.750-05:00Consulta sobre Optimización de Procedimientos AlmacenadosLlegó un correo de un lector: Héctor Hoyos.<br />
<blockquote><i><br />
</i><br />
<i>Buenas noches; soy una persona muy interesada en conocer <a href="http://ikanus3000.blogspot.com/2008/11/probando-y-optimizando-procedimientos.html">como pruebo y optimizo un procedimiento almacenado</a> y de acuerdo con el texto de su blog "Podemos empezar realizando una estadística de la ejecución del procedimiento almacenado, detallando ciclos de CPU utilizados, lecturas, escrituras, tiempo de duración,</i><br />
<i>observaciones, etc. no tengo la experiencia ni el conocimiento para realizar estas estadisticas, me puede orientar que y como ejecutar estas estadisticas.</i><br />
<i><br />
</i><br />
<i>Yo vivo en Colombia y me parece muy interesante su blog, del cual estoy aprendiendo bastante.</i><br />
<i><br />
</i><br />
<i>Cordial saludo,</i><br />
<i><br />
</i><br />
<i>Héctor A. Hoyos B.</i></blockquote><br />
<br />
Mi respuesta fué:<br />
<br />
<blockquote><i>Hola Héctor:</i><br />
<i><br />
</i><br />
<i>En el Analizador de Consultas, en el menú Consulta, marcas la opción Mostrar Estadísticas de Cliente, y cuando ejecutes el procedimiento (en el mismo analizador de consultas), te mostrará las estadisticas de ejecución del procedimiento. Otra es Mostrar plan de ejecución. Ambas te darán estadisticas del procedimiento, que te permitirá optimizarlo.</i><br />
<i><br />
</i><br />
<i>Saludos,</i><br />
<i><br />
</i><br />
<i>Carlos</i></blockquote>Animo a ustedes lectores a hacer preguntas, la verdad que el tiempo siempre es escaso, pero siempre trato de dar una respuesta. Hasta pronto.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1855563562307870254.post-30185834181508366612009-06-17T11:49:00.004-05:002009-06-17T12:17:23.074-05:00Ejecutar una Tarea SQL mediante un Archivo por Lotes o BatchCada persona encargada de una base de datos va a llegar a la situación en que debe realizar tareas de mantenimiento como realizar backups de bases de datos, reindexar tablas y otras tareas similares.<br /><br />Esas tareas idealmente deben ser programadas, y ellas son ejecutadas en una agenda programada. Pero en el caso que la tarea deba ser ejecutada a voluntad ("On Demand", bajo demanda) necesitará intervención humana, y la persona obviamente necesitará tener conocimientos técnicos para poder desarrollarla.<br /><br />Entonces, el reto esta ahí, y es que podamos hacer que cualquier persona, tenga habilidades técnicas o no, pueda ejecutar dichas tareas.<br /><br />Una forma seria utilizar un script VBS y utilizar DMO para ejecutar la tarea. Otra forma, y al parecer más sencilla es ejecutar un comando osql en un archivo por lotes o batch.<br /><br />La utilidad osql permite ejecutar sentencias Transact-SQL, procedimientos de sistema y archivos script. Esta utilidad utiliza ODBC para comunicarse con el servidor.<br /><br /><span style="font-weight: bold;">PRIMER PASO:</span><br />Ver si el trabajo a realizar puede ser ejecutado utilizando osql. Abrimos una ventana de comandos y ejecutamos la siguiente sentencia osql en ella:<br /><br /><span style="font-size:85%;"><span style="font-weight: bold;">osql -S "NOMBRE_INSTANCIA_SERVIDOR" -E -Q"exec msdb.dbo.sp_start_job ' BACKUPTEST ' "</span></span><br /><br /><br />Aquí "NOMBRE_INSTANCIA_SERVIDOR" es el nombre de la instanacia Sql Server ejecutandose en la computadora y sobre la cual se va a ejecutar la tarea. "BACKUPTEST" es el nombre de la tarea que ejecutará el trabajo de mantenimiento deseado. Despues de ejecutar el comando notaras que el procedimiento almacenado de sistema 'sp_start_job' ejecuta la tarea deseada sobre la instancia del servidor elegida.<br /><br /><span style="font-weight: bold;">SEGUNDO PASO:</span><br />El siguiente paso es crear un archivo por lotes. Abre el Bloc de Notas y escribe los siguientes comandos:<br /><br /><span style="font-size:85%;"><span style="font-weight: bold;">ECHO ejecutando tarea</span><br /><span style="font-weight: bold;">ECHO.</span><br /><span style="font-weight: bold;">pause</span><br /><span style="font-weight: bold;">osql -S "NOMBRE_INSTANCIA_SERVIDOR" -E -Q"exec msdb.dbo.sp_start_job ' BACKUPTEST ' "</span><br /><span style="font-weight: bold;">ECHO tarea ejecutada</span><br /><span style="font-weight: bold;">pause</span><br /><span style="font-weight: bold;">CLS</span><br /><span style="font-weight: bold;">EXIT</span></span><br /><br />Guarda el archivo como "Tarea.bat".<br /><br />Luego, el archivo por lotes está listo para ser utilizado. Solo se hace doble click sobre el archivo y el trabajo de mantenimiento se realizará, sin necesidad de tener conocimientos de SQL Server.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1855563562307870254.post-63329617930316499162008-11-17T08:39:00.004-05:002009-03-16T08:36:25.339-05:00Probando y Optimizando Procedimientos Almacenados<span style="font-weight: bold;">Probar y optimizar un procedimiento almacenado</span> es una tarea complicada, más aún cuando el procedimiento no lo hemos escrito nosotros.<br /><br />Un <span style="font-weight: bold;">procedimiento almacenado</span> podría ejecutarse muy lentamente, afectando a la aplicación demandante. Las causas son muchas: hardware, memoria, sistema operativo, red, etc.<br /><br />Podemos empezar realizando una estadística de la <span style="font-weight: bold;">ejecución del procedimiento almacenado</span>, detallando ciclos de CPU utilizados, lecturas, escrituras, tiempo de duración, observaciones, etc.<br /><br />Vamos llevando esos datos mientras realizamos cambios, de modo que podamos tener un control, que cambio afecta o mejora el desempeño del procedimiento.<br /><br />Antes de hacer las mediciones del desempeño de los procedimientos hay que ejecutar las siguientes comandos en el Analizador de Consultas:<br /><br /><pre class="code"><br />DBCC DROPCLEANBUFFERS<br />DBCC FREEPROCCACHE<br /></pre><br />Esto "limpia" los buffers y el cache de Sql Server, de modo que permite un análisis más exacto del <span style="font-weight: bold;">rendimiento del procedimiento</span>. Ya el resto depende de quien analice el procedimiento, aunque podemos revisar los siguientes puntos:<br /><br /><ul><li>Evitar crear tablas temporales, sentencias sql dinamicas y joins. </li><li>Cuidar que la salida del procedimiento almacenado sea la misma que antes de la optimización.</li><li>Debemos de ver cual es la ejecución de cada sentencia DML.</li><li>Evitar los Table Scan.</li><li>Que las sentencias SQL sean escritas en formato ANSI, no ayuda mucho al desempeño, pero si a entenderlas.</li></ul>Como recomendación, siempre hay que pensar de esta forma: <span style="font-weight: bold;">un procedimiento almacenado se puede optimizar</span> para ejecutarse en menos tiempo o para ser de menor tamaño, y no se puede obtener ambos siempre, en el mejor de los casos, hay que decidir que aspecto queremos mejorar.<br /><br />Como se ve no hay reglas exactas para <span style="font-weight: bold;">optimizar procedimientos almacenados</span>, pero si ciertas reglas generales.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-1855563562307870254.post-86665020862143677882008-10-13T17:40:00.004-05:002008-10-13T17:42:59.917-05:00Comprobar si un email es correcto¿como comprobar que la dirección de correo electrónico o e-mail ha sido digitado correctamente? <br /><br />Si es real o no el e-mail, es imposible saberlo, pero por lo menos podemos descubrir si el usuario ha tecleado algo similar a una dirección de correo, si por lo menos tiene dentro el símbolo de la arroba ('@').<br /><br />Declare @DirecionDeCorreo varchar(100)<br />SET @DirecionDeCorreo = 'test@xx.com'<br />If NOT (@DirecionDeCorreo LIKE '[^.@]%[^.@]@[^.@]%[^.@].[^.@]%[^.@]' OR @UserEmail LIKE '%@%@%')<br /> Begin<br /> Print ‘error’<br /> End<br /><br />Podemos adaptarlo, para colocarlo en una función o procedmiento almacenado.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1855563562307870254.post-2825698338389742102008-10-13T17:31:00.003-05:002008-10-13T17:36:04.840-05:00Script para eliminar registros o filas duplicadasGeneralmente, cuando importamos datos a una tabla podemos llegar a tener algunos registros duplicados. El problema es como deshacernos de ellos, sin revisar uno por uno los registros o filas, que en algunos casos pueden pasar de las decenas de miles.<br /><br />Con el siguiente script puede ser más sencillo (hay que adaptarlo segun la tabla):<br /><br />/*******************************************************************/<br />/* Script para eliminar registros duplicados de tabla Empleados */<br />Declare @id int,<br /> @name varchar (50),<br /> @cnt int,<br /> @salary numeric<br /><br />Declare getallrecords cursor local static For<br /> Select count (1), id, name, salary <br /> from employee (nolock)<br /> group by id, name,salary having count(1)>1<br /> <br />Open getallrecords<br /><br />Fetch next from getallrecords into @cnt,@id,@name,@salary<br />--cursor para chequear los otros registros<br />While @@fetch_status=0<br /> Begin<br /> Set @cnt= @cnt-1<br /> Set rowcount @cnt<br /><br /> -- eliminar los registros duplicados. Observa que todos los campos son mencionados -- en la condicion<br /> Delete from employee where id=@id and name=@name<br /> and salary=@salary<br /><br /> Set rowcount 0<br /><br /> Fetch next from getallrecords into @cnt,@id,@name,@salary<br /> End <br /><br />Close getallrecords<br />Deallocate getallrecords<br /><br />*******************************************************************<br /><br />Antes que todo hay que realizar una copia de seguridad, para darnos cuenta como trabaja el script. Lo recomiendo, y antes de ejecutarlo contra datos importantes, pruebalo con una tabla de prueba, no me responsabilizo por pérdida de datos importantes.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1855563562307870254.post-82543001988962806162008-10-13T17:05:00.007-05:002008-10-13T17:24:29.233-05:00Limpiar conexiones no utilizadas (Script)Este script ActiveX corre en el diseñador de DTS y limpiará las conexiones no utilizadas.<br /><br />Esto permite renombrar las conexión, seleccionando Nueva Conexión y tipeando un nuevo nombre.<br /><br />También permite copiar y pegar conexiones para renombrarlas.<br /><br />Luego puedes limpiar las conexiones abandonadas cuando el desarrollo este completo.<br /><table bgcolor="gray" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td><font color="white"><br />'**********************************************************************<br />'* Script ActiveX<br />'**********************************************************************<br />'* Limpiar conexiones no utilizadas<br />'**********************************************************************<br />'* ----------------------------------------<br />'* Descripcion:<br />'* Este script realiza un ciclo a traves de cada conexion en un paquete y la libera '* si no esta siendo utilizada.<br />'* ----------------------------------------<br />'* Uso:<br />'* 1. Agregar una tarea a un paquete DTS.<br />'* 2. Deshabilita esta tarea propiedades del flujo de trabajo, de modo que no se <br />'* ejecute con el paquete.<br />'* 3. Copia este script en la tarea ActiveX.<br />'* 5. Realiza una copia de seguridad del paquete. (No olvidar este paso)<br />'* 6. Guarda el paquete. (No olvidar este paso)<br />'* 7. Ejecutar el script ActiveX en el diseñador DTS, guardar, y cerrar el paquete.<br />'*-------------------------------------------------------------------------------------<br />'* Nota:<br />'* - Este script no debe ser ejecutado sin supervisión.<br />'* - No editar el script en Propiedades del Tarea ActiveX.<br />'* - Editar como un archivo .vbs en, y depura scripts el el Microsoft Script Editor.<br />'-------------------------------------------------------------------------------------<br />Function Main()<br /> On Error Resume Next <br /> Stop<br /> Dim loPackage<br /> Dim loConnections<br /> Dim loConnection<br /> Dim loTasks<br /> Dim loTask<br /> Dim loProperties<br /> Dim loProperty<br /> Dim lbConnectionUsed<br /> Set loPackage = DTSGlobalVariables.Parent<br /> Set loConnections = loPackage.Connections<br /> Set loTasks = loPackage.Tasks<br /> ' Reiniciar despues de cambiar de coleccion<br /> Do<br /> ' Loop Through Connections<br /> For Each loConnection In loConnections<br /> lbConnectionUsed = False<br /> ' Loop Through Tasks<br /> For Each loTask in loTasks<br /> Set loProperties = loTask.Properties<br /> ' Loop Through Properties<br /> For Each loProperty in loProperties<br /> If Instr(loProperty.Name, "ConnectionID") Then<br /> If loProperty = loConnection.ID Then<br /> lbConnectionUsed = True<br /> Exit For<br /> End If<br /> End If<br /> Next<br /> If lbConnectionUsed = True Then<br /> Exit For<br /> End If<br /> Next<br /> If lbConnectionUsed = False Then<br /> loConnections.Remove loConnection.Name<br /> Exit For<br /> End if<br /> Next<br /> If lbConnectionUsed = True Then<br /> Exit Do<br /> End If<br /> Loop<br /> Set loPackage = Nothing<br /> Set loConnections = Nothing<br /> Set loConnection = Nothing<br /> Set loTasks = Nothing<br /> Set loTask = Nothing<br /> Main = DTSTaskExecResult_Success<br />End Function<br /></font><br /></td><br /></tr><br /></tbody></table>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-79129302039622590882008-09-06T20:19:00.002-05:002008-09-06T20:37:33.431-05:00Resumen de Agosto 2008Esta es la lista de entradas mas visitadas en Agosto del 2008:<br /><br /><ol><li><a href="http://www.blogger.com/Visual%20Basic%20y%20Sql%20Server%20con%20Ado%20Data%20Control">Visual Basic y Sql Server con Ado Data Control</a></li><li><a href="http://ikanus3000.blogspot.com/2008/04/conectarse-servidor-sql-server-travs-de.html">Conectarse a Sql Server a través de Internet</a></li><li><a href="http://ikanus3000.blogspot.com/2007/12/como-hacer-una-consulta-por-fecha.html">¿Como hacer una consulta por fechas?</a></li><li><a href="http://ikanus3000.blogspot.com/2008/03/auditora-en-bases-de-datos-sql-server.html">Auditoría en Bases de Datos Sql Server</a></li><li><a href="http://ikanus3000.blogspot.com/2008/06/buenas-practicas-diseno-base-datos.html">Buenas Prácticas en diseño de bases de datos</a></li><li><a href="http://ikanus3000.blogspot.com/2008/02/hp-ipaq-pocket-pc-2003-pda-vb.html">Programar para Pocket PC 2003: Como probar una aplicación que desarrollemos</a></li><li><a href="http://ikanus3000.blogspot.com/2007/12/sql-server-sentencia-where-con.html">Sql Server: Sentencia WHERE con condicionales</a></li><li><a href="http://ikanus3000.blogspot.com/2008/02/base-de-datos-del-ejemplo.html">Base de Datos del Ejemplo de conectar Visual Basic con ADO a Sql Server</a></li><li><a href="http://ikanus3000.blogspot.com/2008/04/hay-diferencia-entre-las-distintas.html">¿Hay diferencia entre las distintas ediciones de Sql Server 2000?</a></li><li><a href="http://ikanus3000.blogspot.com/2007/11/diferencia-entre-truncate-y-delete.html">Diferencia entre Truncate y Delete</a></li></ol>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-37062763863956710062008-08-04T00:11:00.004-05:002008-08-20T22:09:26.397-05:00Consulta sobre Pocket PCHe recibido un correo de Sergio Claver, consultando sobre desarrollo para Pocket PC, no soy un experto pero trataré de responder según lo que sé:<br /><br /><span style="font-weight: bold; font-style: italic;"> siempre he querido hacer programas simples para pocket pc,</span><br /><span style="font-weight: bold; font-style: italic;"> me parecio siempre algo confuso pues leia que varias personas hablaban de net, visual studio, asp, xml, visual basic, embedded, etc.</span><br /><br /><span style="font-weight: bold; font-style: italic;"> Luego averiguando ultimo me entere que microsoft habia tratado de uniformizar todo lanzando kits para desarrolladores.</span><br /><br /><span style="font-weight: bold; font-style: italic;"> Bueno mi pregunta es esta,</span><br /><span style="font-weight: bold; font-style: italic;"> Que tan dificil es crear un programa "bonito" y "simple" tipo los de SPB por ejemplo para calcular areas, que como sabes es tan solo una multiplicacion, suma y resta.</span><br /><br /><span style="font-weight: bold; font-style: italic;"> y otra</span><br /><br /><span style="font-weight: bold; font-style: italic;"> si tengo un traductor de palabras en un formato ejecutable exe para PC que segun el autor es libre de ser modificado, como hago para pasar ese programa de 32bits a pocket pc o mobile ?</span><br /><br /><span style="font-weight: bold; font-style: italic;"></span><br /><br />Respuesta:<br /><br />Hacer un programa para Pocket PC es muy simple, ahora que contamos con Visual Studio 2005/2008. Te sorprenderá saber que es casi programar igual que para Windows, en Visual Studio te dan plantillas y según el lenguaje que uses (yo utilizo Visual Basic) solo algunos comandos no son posibles de usar en Pocket PC. Microsoft proporciona un Mobile SDK para el desarrollo de estas aplicaciones. En esta <a href="http://ikanus3000.blogspot.com/2008/03/visual-basic-sql-server-pocket-pc-2003.html">entrada</a> publiqué algunos enlaces que te pueden ayudar. Luego tienes que saber <a href="http://ikanus3000.blogspot.com/2008/02/hp-ipaq-pocket-pc-2003-pda-vb.html">como probar tu aplicación</a>, sin tener el dispositivo.<br /><br />Ahora, respecto al programa ejecutable para PC, si tienes el código fuente, es dificil pero no imposible "traducirlo" al Pocket PC. Lo importante es tener el código fuente. Ahora sólo habría que ver como te comenté líneas arriba si utiliza sentencias o comandos que no se pueden utilizar en Pocket PC. <br /><br />Espero que haya entre los lectores alguien que conozca más del tema y nos oriente un poco más.<br /><br /><span style="font-weight: bold;">Entradas Relacionadas:</span><br /><ul><li><a href="http://ikanus3000.blogspot.com/2008/03/visual-basic-sql-server-pocket-pc-2003.html" target="_blank">Enlaces de Ayuda para programar Visual Basic y Sql Server en un Pocket PC 2003</a></li><li><a href="http://ikanus3000.blogspot.com/2008/02/hp-ipaq-pocket-pc-2003-pda-vb.html" target="_blank">Programar para Pocket PC 2003: Como probar una aplicación que desarrollemos</a></li><li><a href="http://ikanus3000.blogspot.com/2007/12/programar-para-pocket-pc-2003.html" target="_blank">Programar para Pocket PC 2003</a></li></ul>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-1855563562307870254.post-41632682085488277642008-07-24T10:47:00.003-05:002008-07-24T10:52:47.725-05:00Visual Basic pronto en LinuxVisual Basic es el lenguaje de programación más extendido por el mundo, tal vez por su facilidad de aprendizaje. Sin embargo su origen lo limita a una plataforma. Sólo se pueden programar en Visual Basic aplicaciones Windows.<br /><br />Pero, en el futuro se va a tener la posibilidad de portar aplicaciones Windows hechas en <a href="http://ikanus3000.blogspot.com/">Visual Basic</a> hacia su principal competidor: Linux. El responsable de esta novedad, que aumentará el campo de distribución de aplicaciones desarrolladas en Visual Basic, es el Proyecto Mono.<br /><br />Mono es el nombre de un proyecto de código abierto iniciado por Ximian y actualmente impulsado por Novell (tras su adquisición de Ximian) para crear un grupo de herramientas libres, basadas en GNU/Linux y compatibles con .NET según lo especificado por el ECMA.<br /><br />Los integrantes del Proyecto Mono anunciaron el desarrollo de un compilador para Visual Basic que permitirá ejecutar sus aplicaciones independiente de la plataforma (tienen que soportar Mono) y sin modificaciones de código. <br /><br />¿Será este uno de los resultados de la colaboración entre Microsoft y Novell para aumentar la interoperabilidad entre los sistemas operativos Windows y GNU/Linux? Lo que parece seguro es que esta característica fomentará la migración de mucho software que antes sólo se podía ejecutar bajo Windows a las plataformas del pingüino. <br /><br />Fuente:<br /><a href="http://www.seguilaflecha.com/articles_3544_Visual-Basic-ahora-para-Linux.html" target="_blank">SeguiLaFlecha</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-22657870317885856812008-06-26T15:15:00.002-05:002008-06-26T15:22:39.400-05:00Microsoft Live Labs Volta: Convierte Aplicaciones de Escritorio a Aplicaciones WebVolta es un conjunto de herramientas que permite construir aplicaciones web multicapa aplicando técnicas y patrones familiares. Primero hay que diseñar y construir una aplicación como una aplicación cliente .NET, luego asignar las porciones de la aplicación para ejecutar sobre el servidor y los que se ejecuten en la capa cliente. El compilador crear código JavaScript para la capa cliente, servicios web para la capa servidor, y comunicación, serialización, sincronización, y otro código necesario para unir a las capas.<br /><br />Los desarrolladores pueden desarrollar aplicaciones hacia cualquier explorador de internet o CLR y Volta será el que maneja las complejidades de dividir las capas por ellos.<br /><br />Enlace:<br /><a href="http://labs.live.com/volta/" target="_blank">Volta</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-41888724741468106602008-06-24T20:37:00.006-05:002008-06-25T23:14:46.584-05:00Buenas Practicas en Diseño de Base Datos<span style="font-weight: bold;"><h2>Introducción</h2></span><br /><br />Un DBMS no facilita diseñar correctamente una base de datos. Muchas veces debemos haber pasado por lo mismo. Nos piden diseñar la base de datos para un sistema, entonces procedemos a crear tablas y nombrarlas del modo que se nos ocurra o entendamos, pero cuando empezamos a desarrollar reportes para el sistema, puede ser dificultoso.<br /><br />¿Haces eso? Pues ¡¡para!!. Recuerda que es un trabajo, y es un reflejo de tí como empleado y habla también acerca de tí como persona. Claro que a veces toma tiempo extra para entender el modelo de datos, pero ese tiempo extra pagará dividendos cuando necesites extraer datos o permitir el acceso a ellos de los usuarios.<br /><br />Veamos cual sería una buena forma de llamar a nuestras bases de datos, tablas, columnas, procedimientos almacenados e incluso vistas.<br /><br /><span style="font-weight: bold;"><h2>Convenciones para tablas o vistas</h2></span><br /><table border="1" border cellpadding="0" cellspacing="0" style="color:black;"><tbody><tr><td><span style="font-weight: bold;">Tipo de Tabla o Vista</span></td><td><span style="font-weight: bold;">Sufijo para Tabla</span></td><td><span style="font-weight: bold;">Descripción</span></td></tr><tr><td>Tabla de Históricos</td><td>hist</td><td>Esta tabla almacena información histórica. Típicamente es una relación de una a varios.</td></tr><tr><td>Tabla de Referencia<br /></td><td>ref</td><td>Este tipo de tabla almacena nombres y descripciones. Ej. 1=Perros.</td></tr><tr><td>Snapshot</td><td>current</td><td>Almacena información actualizada, típicamente se utiliza con tablas históricas para almacenar el último registro para una clave externa.</td></tr><tr><td>Primera Instancia</td><td>orig<br /></td><td>Almacena la primera instancia de una clave externa, es lo opuesto al Snapshot, pero contiene los mismo datos si es que sólo hay un registro de la clave externa.</td></tr></tbody></table><br /><br /><span style="font-weight: bold;"><h2>Casos especiales de Vistas</h2></span><br /><br />Muchos DBA no dejan que los usuarios accedan directamente a las tablas, para eso utilizan vistas para las consultas contra las tablas. Es una buena práctica siempre que no haya demasiados joins.<br /><br />Para una vista, podemos nombrarla con una letra "v" o "vw" al comienzo del nombre, que ayuda cuando cuando se lista las vistas fuera del Administrador Corporativo tal como Microsoft Access. Gracias a ese prefijo el usuario puede distinguir si es una vista o una tabla, y cual es el tipo de información almacenada en la tabla y que tipo de tabla es.<br /><br />Notarán que no se indica utilizar un prefijo para una tabla. Esto es para establecer que siempre que un objeto no tenga prefijo es una tabla, y cuando tenga prefijo es una vista o procedimiento almacenado.<br /><br /><span style="font-weight: bold;"><h2>Convenciones para nombrar columnas</h2></span><br /><br />A veces uno tiene reglas para nombrar tablas, vistas o procedimientos almacenados. Sin embargo cuando se trata de columnas no lo tenemos. Una regla que puede ayudarnos mucho y ahorrarnos tiempo es llamar a la columna A de la tabla 1, llamarla también A en la tabla 2. Un simple movimiento que puede salvarnos de muchos problemas.<br /><br /><table><br /><tbody><tr><br /><td><span style="font-weight: bold;">Tipo de Columna</span></td><br /><td><span style="font-weight: bold;">Sufijo de Columna</span></td><br /><td><span style="font-weight: bold;">Descripción</span></td><br /></tr><br /><br /><tr><br /><td>Nombre del elemento</td><br /><td>name</td><br /><td>Usada para describir el nombre de una clave principal</td><br /></tr><br /><br /><tr><br /><td>Descripción del elemento</td><br /><td>desc</td><br /><td>Usada para describir el nombre con más detalle</td><br /></tr><br /><br /><tr><br /><td>Fecha de los datos</td><br /><td>entry_date</td><br /><td>Usada para marcar con fecha una fila</td><br /></tr><br /><br /><tr><br /><td>Usuario que ingresó datos</td><br /><td>ingresado_por</td><br /><td>Usada para registrar que usuario o aplicación introdujo los datos</td><br /></tr><br /><br /><br /><tr><br /><td>Fecha de actualización de los datos</td><br /><td>update_date</td><br /><td>Muestra la fecha en que se actualizaron los datos</td><br /></tr><br /><br /><br /><tr><br /><td>Usuario que actualizó los datos</td><br /><td>modificado_por</td><br /><td>Utilizada para almacenar el usuario que modificó los datos</td><br /></tr><br /><br /><br /><tr><br /><td>Clave primaria númerica</td><br /><td><<<nombre>>>_id</nombre></td><br /><td>Utilizada describir la clave primaria cuando la clave es un valor númerico</td><br /></tr><br /><br /></tbody></table><br /><br /><span style="font-weight: bold;"><h2>Procedimientos Almacenados</h2></span><br /><br />Una convenció que puede utilizarse es 'usr_<<nombre descriptivo="">>, de modo que cuando se depure la aplicación se sabe que un objeto con 'usr_' es un procedimiento almacenado. Hay que incluir dentro del nombre algo que indique que es lo que hace el procedimiento almacenado. Por ejemplo si un procedimiento almacenado actualiza la categoría de un producto, se le puede llamar 'usr_ActualizarCategoria'.<br /><br /><span style="font-weight: bold;"><h2>Bases de Datos</h2></span><br /><br />Ultimamente el uso de una convención para llama a la base de datos. Similar a la convención de nombres para procedimientos almacenados, como usar el prefijo 'dev' y 'prod' para distinguir entre una base de datos de desarrollo y una de producción.<br /><br /><span style="font-weight: bold;"><h2>Conclusión</h2></span><br /><br />Las convenciones de nombres que menciono no son dificiles de seguir. Usualmente, bueno, casi siempre somos presionados en el tiempo para diseñar una base de datos. No hay que sentirse mal por eso, no es nuestra culpa. Pero hay que tomarnos el tiempo para establecer y seguir nuestras convenciones de nombres. Tres meses después, cuando revisemos el código nos agradeceremos a nosotros mismos por eso. La clave de todo esto es ser consistente. Si somos consistentes, modificar el código será mucho más fácil.<br /><br />¿Ustedes tienen alguna convención de nombres?</nombre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-14878757713402675362008-06-01T19:46:00.004-05:002008-06-25T23:15:51.687-05:00Mejores Practicas en Desarrollo para Sql ServerSi, hay <a href="http://ikanus3000.blogspot.com/2008/06/buenas-practicas-diseno-base-datos.html">prácticas buenas</a> y hay prácticas malas en Sql Server.<br /><br /><span style="font-weight: bold;"><h2>¿Que pasa si no se siguen las buenas prácticas?</h2></span><br /><br />Pasa, que vas a empezar a decir y escuchar cosas como estas:<br /><br />- ¡Qué raro! En mi casa funcionaba<br />- El usuario sa debe tener una clave determinada<br />- ¿Añadir ese dato en la tabla clientes? No creo que se pueda...<br /><br /><span style="font-weight: bold;"><h2>Lista de buenas prácticas:</h2></span><br /><br /><span style="font-weight: bold;">- Gestión del código fuente:</span> no sólo producción debe tener lo último, debe haber un control de versiones.<br /><span style="font-weight: bold;">- Gestión del esquema:</span> importación del esquema, ingeniería inversa, esquemas en SQL, organización del esquema (por tipo de objeto, por esquema), tareas pre y post deployment, refactorización, más de un fichero por objeto.<br /><span style="font-weight: bold;">- Comparaciones de objetos:</span> de esquemas, diferencias entre versiones, generación de scripts de diferencias, actualización, creación y borrado de objetos.<br /><span style="font-weight: bold;">- Pruebas en bases de datos:</span> pruebas de carga (con datos), datos de producción o datos inventados, probar integridad referencial.<br /><span style="font-weight: bold;">- Pruebas en las bases de datos:</span> pruebas unitarias (script anterior, prueba, script posterior), pre y post condiciones.<br /><span style="font-weight: bold;">- Generación e implementación:</span> consolidación de varios scripts.<br /><span style="font-weight: bold;">- Otras buenas prácticas:</span> vistas y vistas indexadas, procedimientos almacenados, desencadenadores (triggers) DDL y DML, services brokes en aplicaciones.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1855563562307870254.post-89672863046100296522008-05-03T19:45:00.003-05:002008-06-25T23:16:20.908-05:00SQL Server 2008 Database Backup CompressionSQL Server 2008 Database Backup Compression una nueva herramienta desarrollada por Microsoft, especialmente diseñada para los administradores y profesionales TIC que hacen copias de seguridad o backups y recuperación de bases de datos en SQL Server 2008.<br /><br />Microsoft asegura que aunque la utilización del CPU aumenta debido a la tarea adicional de compresión, el tiempo de hacer un backup de la base de datos se reduce considerablemente.<br /><br />Esta herramienta funciona en la versión 2008 de <a href="http://ikanus3000.blogspot.com/">Sql Server</a>, para versiones anteriores pueden utilizar una alternativa de <a href="http://ikanus3000.blogspot.com/2007/12/backups-con-winrar-de-bases-de-datos.html">backups con Winrar</a>.<br /><br /><span style="font-weight: bold;">Enlaces:</span><br /><a href="http://www.vnunet.es/es/vnunet/news/2008/04/03/microsoft_lanza_sql_server_2008_database_backup_compression" target="_blank">Vnunet.es</a><br /><a href="http://edge.technet.com/Media/SQL-Server-2008-Database-Backup-Compression/" target="_blank">Microsoft Technet</a>Unknownnoreply@blogger.com0