sábado, 21 de julio de 2012

SQL Server trunca divisiones de enteros

Pues eso, revisando una función que entre otras acciones divide dos números enteros (entiéndase dos datos de tipo int)descubrí que sql server trunca el resultado. Aunque esto está claramente documentado en los libros en pantalla me tomó por asalto. Esto puede resultar una verdadera catástrofe para aquellos novatos o algunos con un poquito mas de experiencia que nos descuidamos.
DECLARE @dividendo int, @divisor int

set @dividendo = 50;
set @divisor = 12;

SELECT (@dividendo/@divisor)
GO
El resultado para esta simple operación no es el deseado, puesto que retorna 4 en lugar de 4.166
DECLARE @dividendo int, @divisor int

set @dividendo = 50;
set @divisor = 12;

SELECT (cast(@dividendo as decimal(18,6))/cast(@divisor as decimal(18,6)))
GO
Ahora si obtenemos el dato que realmente necesitamos.
Saludos.

domingo, 17 de junio de 2012

Como Hacer Reporte Crystal Reports y Asp .Net

Recientemente una amiga me pidio ayuda para hacer un reporte rápido con crystal reports y asp .net.

El ejemplo que hice para ella y que hoy comparto con usted hace uso del wizard de visual studio válido para las versiones 2005 y 2008. Sé que habrá quienes digan que esta no es la mejor manera de hacerlo, quienes lo hagan seguramente ya tienen experiencia en esto, sin embargo el ejemplo está dirigido para principiantes. En otra ocasión compartiré otro método. Por lo pronto acá les dejo el enlace del video en youtube y el código fuente:

Imports CrystalDecisions.Shared
Imports CrystalDecisions.CrystalReports.Engine
Partial Class _Default
    Inherits System.Web.UI.Page
    Private Sub configureCRYSTALREPORT()

        Dim myConnectionInfo As New ConnectionInfo()
        myConnectionInfo.ServerName = "NOMBRE_O_IP_DEL_SERVIDOR"
        myConnectionInfo.DatabaseName = "Northwind"
        myConnectionInfo.UserID = "sa"
        myConnectionInfo.Password = "myserver"
        setDBLOGONforREPORT(myConnectionInfo)

    End Sub

    Private Sub setDBLOGONforREPORT(ByVal myconnectioninfo As ConnectionInfo)

        Dim mytableloginfos As New TableLogOnInfos()
        mytableloginfos = CrystalReportViewer1.LogOnInfo

        For Each myTableLogOnInfo As TableLogOnInfo In mytableloginfos
            myTableLogOnInfo.ConnectionInfo = myconnectioninfo
        Next

    End Sub

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        configureCRYSTALREPORT()
    End Sub
End Class


Me han solicitado el código en c#. Acá se los dejo.
using CrystalDecisions.Shared;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Web;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        configureCRYSTALREPORT();
    }

    private void configureCRYSTALREPORT()
    {
        ConnectionInfo myConnectionInfo = new ConnectionInfo();
        myConnectionInfo.ServerName = "NOMBRE_O_IP_DEL_SERVIDOR";
        myConnectionInfo.DatabaseName = "Northwind";
        myConnectionInfo.UserID = "sa";
        myConnectionInfo.Password = "mipassword";
        setDBLOGONforREPORT(myConnectionInfo);
 
    }
 
    private void setDBLOGONforREPORT(ConnectionInfo myconnectioninfo)
    {
        TableLogOnInfos mytableloginfos = new TableLogOnInfos();
        mytableloginfos = CrystalReportViewer1.LogOnInfo;
     
        foreach (TableLogOnInfo myTableLogOnInfo  in mytableloginfos)
        {
            myTableLogOnInfo.ConnectionInfo = myconnectioninfo;
        }
     
    }

}
Si desean usar la autenticacion de windows en lugar de autenticacion de sql server cambian las lineas correspondientes al UserID y Password por lo siguiente:
myConnectionInfo.IntegratedSecurity = true;

Para evitar que durante la publicación recuerde los datos de prueba deben activar la opción Discard Saved Data When Loading Reports en las imagenes siguientes muestro como hacerlo

Saludos.

domingo, 4 de marzo de 2012

Como fijar el precio de tu trabajo?

Ayer tuve una experiencia que me hizo recordar una historia que leí en la universidad hace algunos años. La historia dice así:

"Algunas veces es un error juzgar el valor de una actividad simplemente por el tiempo que toma realizarla… Un buen ejemplo es el caso del ingeniero que fue llamado a arreglar una computadora muy grande y extremadamente compleja… una computadora que valía 12 millones de dólares.
Sentado frente a la pantalla, oprimió unas cuantas teclas, asintió con la cabeza, murmuró algo para sí mismo y apagó el aparato. Procedió a sacar un pequeño destornillador de su bolsillo y dio vuelta y media a un minúsculo tornillo. Entonces encendió de nuevo la computadora y comprobó que estaba trabajando perfectamente. El presidente de la compañía se mostró encantado y se ofreció a pagar la cuenta en el acto. - ¿Cuánto le debo? -preguntó. - Son mil dólares, si me hace el favor. - ¿Mil dólares? ¿Mil dólares por unos momentos de trabajo? ¿Mil dólares por apretar un simple tornillito? ¡Ya sé que mi computadora cuesta 12 millones de dólares, pero mil dólares es una cantidad disparatada! La pagaré sólo si me manda una factura perfectamente detallada que lo justifique. El ingeniero asintió con la cabeza y se fue. A la mañana siguiente, el presidente recibió la factura, la leyó con cuidado, sacudió la cabeza y procedió a pagarla en el acto, sin chistar.
La factura decía:
Servicios prestados:
Apretar un tornillo:…………. 1 dólar 
Saber qué tornillo apretar: 999 dólares
Total:………………………… 1.000 dólares"


Por qué lo recordé? Pues porque me sucedió lo mismo. Fui llamado de emergencia para atender un problema con un servidor de una empresa X. Hice mi trabajo en un tiempo relativamente corto. Desafortunadamente al momento de cobrar mis clientes no fueron tan comprensivos como el presidente de la compañía de la historia. El mundo real es así, existen empresarios a los que poco les importa el tiempo, dinero y esfuerzo invertido en tu preparación profesional, ellos quieren poner precio a tu trabajo.

Todo aquel que, al igual que yo, realiza trabajos como FreeLancer enfrenta este tipo situaciones. Y nos hacemos la pregunta ¿Como debemos fijar el precio de nuestro trabajo? Personalmente escojo de entre las siguientes opciones:

  • Fijar el precio antes de hacer el trabajo. Es recomendable cuando realizas un trabajo "mecánico". Es decir tareas para las que las soluciones son obvias, o que no necesariamente involucran solucionar algún problema. Ejemplo de esto pueden ser el mantenimiento preventivo de pc, instalación y/o actualización de software, configuraciones básicas del s.o, instalación de hardware, cableado de red, etc. 
    • Ventaja: Si el cliente no acepta tu precio puedes dar media vuelta e irte sin mover un solo dedo.
    • Desventaja: Corres el riesgo de encontrarte con una situación imprevista  que demande mucho mas tiempo y esfuerzo que no serán remunerados.
  • Realizar un diagnostico, luego fijar el precio. Aconsejo este método para casos en los que "hay un problema" y según nuestra experiencia sabemos de manera precisa las posibles soluciones a aplicar.
    • Ventaja: Fijarás un precio con el que al final estarás satisfecho.
    • Desventaja: El diagnostico "ya es trabajo", es esfuerzo y tiempo que no será remunerado si el cliente decide no hacer uso de tus servicios.
Personalmente esta es la opción que uso cuando el encargo es el desarrollo de alguna aplicación o diseño de sitio web. Ustedes ya sabrán que primero es el análisis de requerimientos. En este ultimo ejemplo lo ideal es dejar el acuerdo por escrito.
  • Realizar todo el trabajo luego fijar el precio. Si, si... está ultima opción es la que llevo a escribir este artículo. Sin embargo hay ocasiones en las que el pc o servidor presenta comportamiento  tipo poltergeist. Esas ocasiones en las que toda tu experiencia acumulada no es suficiente para explicar de forma precisa el mal funcionamiento del hardware o software. Entonces tienes que recurrir a probar múltiples opciones de solución o invocar al CHapulin Colorado, jeje. Al final lo justo es cobrar por todo el esfuerzo y tiempo invertido y no solo por la solución que a fin cuentas funcionó.
Cualquiera de estas opciones las aplico considerando los precios en el mercado para cada servicio procurando siempre un precio justo para el cliente y para mí.

Esta es una humilde apreciación, y tu que opinas?

P.D.: Agradezco los comentarios constructivos.

domingo, 19 de febrero de 2012

Cerrar Todas Las Conexiones A Base De Datos SQL Server

Hola amigos. Hace algún tiempo un amigo me compartió este script que encontró en SQLServerCentral. Su finalidad es cerrar todas las conexiones existentes a una base de datos SQL Server. Solamente necesitas pasarle como parámetro el nombre de la base de datos. Lo he aplicado en SQL Server 2005 y funciona sin problemas.
Aunque no he trabajado como DBA en mi trabajo como desarrollador me ha sido de mucha utilidad. Espero le s sea útil a ustedes también.


/*

* Author Rafal Skotak

* Purpose Procedure tries to kill all connections to the specified database

*

* Date 2011.02.18

*

******************************************************************************************************/

USE [master]

GO

CREATE PROCEDURE proc_kill_dbconnections

@dbname SYSNAME

with encryption

as

begin

set nocount on



------- prepare temporary tables

-------------------------------------------

create table #temp_processes_table

(

spid int primary key,

ecid int,

status sysname,

loginame sysname null,

hostname sysname null,

blk int,

dbname sysname null,

cmd sysname null,

request_id int null,

mod int not null default 0

);



-- get processes list

--------------------------

insert into #temp_processes_table (spid, ecid, status, loginame, hostname, blk, dbname, cmd, request_id)

exec sp_who



declare @count int

declare @process_id int

declare @cmd varchar(8000)



select @count = count(*) from #temp_processes_table where mod = 0



while @count > 0

begin

set @process_id = NULL



select top 1 @process_id = spid from #temp_processes_table where mod = 0 and dbname = @dbname



if @process_id is NULL

break



print @process_id



set @cmd = 'kill ' + cast(@process_id as varchar)



exec (@cmd)



update #temp_processes_table set mod = 1 where spid = @process_id



select @count = count(*) from #temp_processes_table where mod = 0 and dbname = @dbname

end



-- cleanup - drop temporary tables

---------------------------------------

drop table #temp_processes_table

end

go



-- example



-- exec dbo.proc_kill_dbconnections 'dbCuentasxCobrar'

domingo, 4 de diciembre de 2011

DICCIONARIO DE DATOS CON SQL SERVER

En internet hay varios ejemplos que abordan este tema sin embargo ninguno de ellos me ha terminado de gustar, de manera rapida escribo este script que hace el trabajo que 'por ahora' requiero. En otra oportunidad profundizaré mas en el tema. Para este ejemplo hago uso basicamente de: INFORMATION_SCHEMA.TABLES para obtener informacion de las tablas de la bd e INFORMATION_SCHEMA.COLUMNS para obtener informacion de cada columna por cada tabla. Sin mas preambulo aca el script:
SET NOCOUNT ON

DECLARE @NOMBRE_TABLA sysname
DECLARE @iColumna int,@iUltimaColumna int,
  @NombreColumna sysname,
  @TipoColumna sysname,
  @Longitud int

SELECT @NOMBRE_TABLA = MIN(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_TYPE= 'BASE TABLE' AND TABLE_NAME!= 'sysdiagrams'

WHILE @NOMBRE_TABLA IS NOT NULL
BEGIN
 PRINT '======================' + @NOMBRE_TABLA + ':========================='
 
 SELECT @iColumna = 0, @iUltimaColumna = max(ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @NOMBRE_TABLA

 WHILE @iColumna < @iUltimaColumna
 BEGIN
  SELECT @iColumna = min(ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_NAME = @NOMBRE_TABLA and ORDINAL_POSITION > @iColumna;
  --
  SELECT @NombreColumna = IC.COLUMN_NAME, @TipoColumna = IC.DATA_TYPE,  
  @Longitud = CASE WHEN CAST(IC.DATA_TYPE AS NVARCHAR) IN ('char','nchar','varchar','nvarchar','text','ntext') THEN IC.CHARACTER_MAXIMUM_LENGTH ELSE NULL END
  FROM INFORMATION_SCHEMA.COLUMNS IC
  WHERE IC.TABLE_NAME = @NOMBRE_TABLA and IC.ORDINAL_POSITION = @iColumna;
  PRINT '. '+ @NombreColumna +  ' ' + @TipoColumna + ' ' + ISNULL(CAST(@Longitud AS NVARCHAR(64)),'')
  --
 END
 
 SELECT @NOMBRE_TABLA= MIN(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME> @NOMBRE_TABLA
 AND TABLE_TYPE= 'BASE TABLE' AND TABLE_NAME!= 'sysdiagrams'
END

lunes, 17 de octubre de 2011

Crear Texto Estilo TRANSFORMERS


Hace algún tiempo encontré esta nota 100 efectos de texto en photoshop, muchos de ellos son realmente alucinantes. Por aquellos días uno de los temas de moda era la ultima pelicula de Transformers; así que para aprovechar esto decidí traducir el tutorial relacionado e introducirlo como ejemplo en la clase de la U. Sin mas preámbulo acá les dejo el resultado:

Paso 1

Como nuestra intención es reproducir el texto original de transformers, es importante que tengas el tipo de letra (font) indicada. Haz click aquí para descargar sf transrobotics.

Crea un nuevo documento (como mínimo 540x300 en 72ppi). Presiona la tecla D para resetear el color de frontal y color de  fondo a negro y blanco respectivamente, seguidamente presione Alt + Backspace para rellenar la capa de fondo con negro.

Cambia el color frontal a blanco presionando X para intercambiar entre color frontal y de fondo, seguidamente selecciona la herramienta texto de la barra o actívala presionando la tecla T, escribe el texto en el tamaño que desees, en mi caso 100pt.

Paso 2
En el logo original de del Logo de Transformers las letras T y F se extienden por debajo del resto de letras del resto de caracteres de la palabra. Para conseguir esto necesitamos raterizar haciendo click con el botón derecho del mouse sobre la capa del texto en nuestra paleta de capas y selecciona Rasterizar texto del menú. Esto habilitara la edición carácter a carácter de la capa texto como un grafico estándar.
Paso 3
Con el texto renderizado con un grafico podemos usar la herramienta Marco Rectangular (actívala presionando M) para seleccionar la parte inferior de las letras T y F y usar  la herramienta Transformacion Libre (puedes invocarla desde el menú edición) para alargarlas.

Paso 4
Con las letras extendidas puedes borrar las guía seleccionando Vista>Borrar guía del menú principal.
Paso 5
Seguidamente crearemos un efecto 3D agregando el efecto Bisel y Relieve a nuestro capa texto y luego duplicando y moviendo esa capa repetidamente.
Primero, establecemos el estilo de capa. Doble click a la derecha del nombre de la capa en la paleta de capas para traer al frente la ventana de Estilo de Capa (*nota: También puedes hacerlo clicando con el botón derecho sobre la capa y seleccionando Opciones de Fusión).
En la columna izquierda de la venta de estilo de capas click sobre Bisel y Relieve y aplica las siguientes configuraciones después click en aceptar para aplicar el estilo de capa.

Paso 6
Por aplicar el estilo Bisel y Relieve hemos creado el borde obscuro que será visible en el próximo paso.

Paso 7
Para crear la ilusión de texto 3D ahora duplicaremos la capa múltiples veces, cada vez cambiar el texto hacia arriba y la derecha.
Para duplicar la capa seleccionada simplemente presiona Ctrl + J o selecciona Capa>Duplicar capa del menú principal. Esto crea una nueva capa sobre la capa seleccionada.
Para cambiar el texto, asegúrese de tener seleccionada la herramienta Mover presionando la tecla V, luego usando las flechas de tu teclado presiona la tecla Up (arriba) y luego la tecla Right una vez cada una. Repite el proceso de duplicar y mover 3 veces debes tener hasta un total de 5 copias de capa.

Paso 8
A estas alturas yo recomendaría fusionar las 4 capas inferiores de nuestras 5 capas 3D haciendo clic en la segunda capa de arriba, mientras presionando la tecla Shift  y seleccionando la capa inferior, seleccionando todas las 4 capas que comprenden el  borde 3D eficazmente. Presiona Ctrl+E para fusionar las capas seleccionadas. 

Nosotros no queremos estilo de capa Bisel y Relieve en la capa de encima, click con el botón derecho en el icono de estilo de capa de la capa de la cima y escoge Borrar Estilo de Capa. Además haz doble clic en los nombres de la capa y cámbialos nombres a los "TRANSFORMERS Top" y "TRANSFORMERS 3D."


Paso 9
Con la capa "TRANSFORMERS Top" seleccionada vamos a agregar una serie de 5 estilos de capa que darán a la capas una apariencia de piedra vieja. Pondré cada uno de los estilos de la capa en serie aquí todo lo que necesitas es bajar en la lista y aplicarlos. Si hay algo excepcional se señalará en las cajas amarillas.
Click con el botón derecho a la derecha del nombre de la capa y aplica los siguientes 5 estilos. Click en Aceptar cuando los hayas agregado.



  • El motivo seleccionado es Marmol Negro de la galería motivos de roca
El código del color es #31464F. Simplemente haz click sobre el visor para lanzar en el selector de color y digita el número de 6 dígitos en el texto de abajo
Paso 10
Hasta aquí el documente debería lucir así:


Paso 11
Observando el efecto es obvio que los 3D bordes son demasiado ligeros. Para resolver este problema, haga clic en la capa "TRANSFORMERS 3D" para seleccionarla, luego cargue la ventana Niveles presionando las teclas Ctrl + L. Arrastra el deslizador de la mano izquierdo en hacia el medio hasta que los bordes 3D parezcan correctos.

Paso 12
Para finalizar la imagen agreguemos una reflexión duplicando la capa el texto y capa 3D, fusionándolos, volteándolos verticalmente, reducir la opacidad a 30% y agregando una máscara de capa con degradado



Agradezco sus comentarios.

jueves, 13 de octubre de 2011

CIFRADO PLAYFAIR EN SQL SERVER

Recientemente me fue solicitada ayuda para eloborar una función que encriptara una frase usando el algoritmo de Cifrado de Playfair.

Crearemos una funcion llamada fnEncriptar que recibirá 2 parametros de tipo nvarchar: @entrada nvarchar(MAX) y @clave(25). Para este ejemplo usaré las misma frase (entrada) y clave usados en el artículo de wikipedia.

El primer paso es suprimir los espacios en blanco y opcionalmente pasamos la frase y clave a mayusculas.

SELECT @entrada = REPLACE(@entrada,' ','')
SET @entrada = UPPER(@entrada)
SELECT @clave = REPLACE(@clave,' ','')
SET @clave=UPPER(@clave)

Seguidamente generamos los poligramas aplicando las reglas y los almacenamos en una variable de tabla.

DECLARE @poligrama TABLE(Idp INT IDENTITY(1,1), par NVARCHAR(2) NOT NULL)
DECLARE @tam int,@pos INT
SET @tam=LEN(@entrada)
SET @pos=1
WHILE @pos<=@tam
BEGIN
 IF (@pos+1)>@tam
  INSERT INTO @poligrama(par)VALUES(SUBSTRING (@entrada,@pos,1)+'X')
 ELSE
  IF SUBSTRING (@entrada,@pos,1)=SUBSTRING (@entrada,@pos+1,1)
   INSERT INTO @poligrama(par)VALUES(SUBSTRING (@entrada,@pos,1)+'X')
  ELSE
   INSERT INTO @poligrama(par)VALUES(SUBSTRING (@entrada,@pos,2))
 SET @pos=@pos+2
END

A esta altura si hacemos un SELECT a la tabla poligramas tendremos el siguiente resultado:


Ahora procederemos aplicamos la regla a la contraseña eliminaremos los caracteres repetidos.

DECLARE @claveReducida NVARCHAR(25)
SET @tam=LEN(@clave)
SET @pos=1
SET @claveReducida=''
WHILE @pos<=@tam
BEGIN
 IF CHARINDEX(SUBSTRING(@clave,@pos,1),@claveReducida)=0
  SET @claveReducida=@claveReducida+SUBSTRING(@clave,@pos,1)
  SET @pos = @pos +1
END
El siguiente paso es crear la matriz de encriptación (de intercambio) de caracteres.

NORIA
BCDEF
GHKLM
PQSTU
VWXYZ

Los primeros elementos de la matriz deben ser los caracteres de la clave:

DECLARE @Matriz TABLE (FILA TINYINT, COLUMNA TINYINT, LETRA NVARCHAR(1))
DECLARE @fmz TINYINT, @cmz TINYINT
SET @pos = 1
SET @tam = LEN(@claveReducida)
SET @fmz=1
WHILE @fmz<=5 AND @pos<=@tam
BEGIN
 SET @cmz=1
 WHILE @cmz<=5 AND @pos<=@tam
 BEGIN
  INSERT INTO @Matriz(FILA, COLUMNA, LETRA)
  VALUES(@fmz,@cmz,SUBSTRING(@claveReducida,@pos,1))
  SET @pos = @pos + 1
  SET @cmz= @cmz + 1
 END
 SET @fmz= @fmz + 1
END
Debe completarse la fila inconclusa con caracteres del alfabeto que no esten en la clave.


--GENERAR EL ALFABETO
DECLARE @iL tinyint, @MaxiL tinyint
--MAYUSCULAS
SET @iL = 65
SET @MaxiL = 90
--minusculas
--SET @iL = 97
--SET @MaxiL = 122
WHILE @cmz<=5
BEGIN
 WHILE @iL <= @MaxiL AND @cmz<=5
 BEGIN
  IF CHAR(@iL) <> 'J' AND NOT EXISTS(SELECT * FROM @Matriz m WHERE m.LETRA = CHAR(@iL))
  BEGIN
   INSERT INTO @Matriz(FILA, COLUMNA, LETRA)
   VALUES(@fmz,@cmz,CHAR(@iL))
   --
   SET @cmz= @cmz + 1
  END
  SET @iL = @iL + 1
 END
END

Una vez hecho esto se completa la matriz al igual que el caso anterior excluyendo las J

WHILE @fmz<=5 AND (@iL<=@MaxiL)
BEGIN
 SET @cmz=1
 WHILE @cmz<=5 AND (@iL<=@MaxiL)
 BEGIN
  IF CHAR(@iL) <> 'J' AND NOT EXISTS(SELECT * FROM @Matriz m WHERE m.LETRA = CHAR(@iL))
  BEGIN
   INSERT INTO @Matriz(FILA, COLUMNA, LETRA)
   VALUES(@fmz,@cmz,CHAR(@iL))
   --
   SET @cmz= @cmz + 1
  END
 --
  SET @iL = @iL + 1
 END
 SET @fmz= @fmz + 1
END
Acá muestro parcialmente el resultado del segmento anterior

Ahora que se ha construido la matriz procedemos al intercambio de caracteres aplicando las reglas:

DECLARE @pgCount INT,@pgRow INT, @fila1 TINYINT, @fila2 TINYINT, @columna1 TINYINT, @columna2 TINYINT, @temp TINYINT
DECLARE @car1 NVARCHAR(1), @car2 NVARCHAR(1),@ncar1 NVARCHAR(1),@ncar2 NVARCHAR(1)

SELECT @pgCount = COUNT(*) FROM @poligrama p
SET @pgRow = 1
SET @SalidaEncriptada = ''

WHILE @pgRow <= @pgCount
BEGIN
 --obtener los caracteres
 SELECT @car1 = SUBSTRING(p.par,1,1),@car2=SUBSTRING(p.par,2,1) FROM @poligrama p
 WHERE p.Idp = @pgRow
 --sustituir j por i

 if @car1 = 'J'
 SET @car1 = 'I'
 if @car2 = 'J'
 SET @car2 = 'I'

 --obtener la posicion de los caracteres en la matriz
 SELECT @fila1=m.FILA, @columna1 = m.COLUMNA FROM @Matriz m WHERE m.LETRA = @car1;
 SELECT @fila2=m.FILA, @columna2 = m.COLUMNA FROM @Matriz m WHERE m.LETRA = @car2;
 --APLICAR REGLAS
 IF @fila1=@fila2 --misma fila
 BEGIN
  IF @columna1<5
  BEGIN
   SET @columna1 = @columna1 +1
  END
  ELSE
  BEGIN
   SET @columna1 = 1
  END
 --
  IF @columna2<5
  BEGIN
   SET @columna2 = @columna2 +1
  END
  ELSE
  BEGIN
   SET @columna2 = 1
  END
 END
ELSE
BEGIN
 IF @columna1=@columna2 -- misma columna
 BEGIN
  IF @fila1<5
  BEGIN
   SET @fila1 = @fila1 +1
  END
  ELSE
  BEGIN
   SET @fila1 = 1
  END
  --
  IF @fila2<5
  BEGIN
   SET @fila2 = @fila2 +1
  END
  ELSE
  BEGIN
   SET @fila2 = 1
  END
 END
 ELSE
  BEGIN
   SET @temp = @columna1
   SET @columna1 = @columna2
   SET @columna2 = @temp
  END
END
--Obtener caracter 1
SELECT @ncar1=m.LETRA FROM @Matriz m WHERE m.FILA = @fila1 AND m.COLUMNA = @columna1;
--Obtener caracter 2
SELECT @ncar2=m.LETRA FROM @Matriz m WHERE m.FILA = @fila2 AND m.COLUMNA = @columna2;

SET @SalidaEncriptada = @SalidaEncriptada + @ncar1 + @ncar2
SET @pgRow = @pgRow + 1
END
RETURN @SalidaEncriptada

Eso es todo amigos. Acá el resultado final.

Espero que les sea de utilidad. Agredezco sus comentarios constructivos.