April 2007 - Artículos

Un post mío en MSDN Estudiantes...

Acabo de ver en la página de MSDN Estudiantes que han publicado uno de mis post de SQL Server 2005, es una buena noticia saber que lo que escribo tiene valor y que mucha más gente se beneficiará. Muchas gracias!.

Este es el link: http://www.microsoft.com/spanish/msdn/latam/estudiantes/articulos/nota2.aspx 

Percy Reyes.

Publicado por Percy Reyes | 11 comment(s)

GDI+ (Parte III) : FORMAS BÁSICAS

Este es otro de los muchos artículos que escribí para el www.elguille.info donde se detalla las formas básicas GDI+: PUNTO,LÍNEA, LA ESTRUCTURA RECTANGLE, ELIPSE, ARCO, POLÍGONO, CURVAS CARDINALES, LOADING ICONS, DRAWPIE, DRAWSTRING, MEASURESTRING, DRAWPATH.

Revisemos la manera de usar GDI++ para dibujar formas básicas como por ejemplo, puntos, líneas, rectángulos, círculos, elipses, y también algunas formas irregulares, todo esto será tratado en este CAPÍTULO III.

Nota: Todo las representaciones se hará sobre un objeto TextBox.

PUNTO

El punto es la forma más sencilla de crear, necesitando para ello dos valores tipo entero que representarán las coordenadas X y Y . El punto es el componente primitivo para dibujar cualquier otra forma, como por ejemplo: líneas, rectángulos, elipses... ahora vamos a crear un objeto punto.

      Dim myPoint As Point = New Point(130, 70)

La representación de un punto la haremos definiendo un círculo muy pequeño. Así:


Dim myPoint As Point = New Point(130, 170)
Dim myLapicero As New Pen(Color.Red, 1)
Me.TextBox1.CreateGraphics.DrawEllipse(myLapicero, New Rectangle(myPoint, New Size(1, 1)))

LÍNEA

Para representar una línea nesecitamos de un objeto Pen y dos puntos, las cuales serán unidas usando el método DrawLine. Ejemplo:


Dim myStartPoint As Point = New Point(130, 170)
Dim myEndPoint As Point = New Point(230, 270)
Dim myLapicero As New Pen(Color.Peru, 2)
Me.TextBox1.CreateGraphics.DrawLine(myLapicero, myStartPoint, myEndPoint)

Así como el método DrawLine nos ayuda a represeenta una línea, existe el método DrawLines que nos permite representar  línea quebradas, recibiendo como parámetros un objeto Pen y un array de puntos.  Ejemplo.

'creando el Pen
Dim myLapicero As New Pen(Color.Peru, 2)

'creando los puntos
Dim myStartPoint As Point = New Point(130, 170)
Dim myPoint2 As Point = New Point(130, 70)
Dim myPoint3 As Point = New Point(230, 170)
Dim myEndPoint As Point = New Point(230, 70)

'creo el array de puntos
Dim myArrayPoints() As Point = New Point() {myStartPoint, myPoint2, myPoint3, myEndPoint}

'representado la línea quebrada, quedando una letra N
Me.TextBox1.CreateGraphics.DrawLines(myLapicero, myArrayPoints)

Otro punto interesante de este artículo es la curva Bézier.

LA CURVA BÉZIER

Para representar una curva bézier usaremos el método DrawBezier la cual se define por cuatro estructuras Point. Una curva Bézier está compuesta por sus puntos inicial y final y dos puntos de control. La función de los puntos de control no es que la curva pase por ellos, sino influenciar su dirección. Lo veremos con un ejemplo. La línea de color azul es la curva Bézier. Cada punto de control está unido por una línea imaginaria con su punto: el primero, con el inicial de la curva, y el segundo con el final. Pues bien, la curva inicia su recorrido en la dirección de la primera línea imaginaria, pero, a medida que avanza, rectifica su dirección para adecuarse a la que le marca la segunda línea imaginaria. Para entender mejor la función de los puntos de control pues tómelo como si estos puntos jalarán en su dirección, tanto el punto inicial como el punto final,  generándo curvas forzadas dándole cierta inflexión a la recta. ¿entendió...?, espero que sí. Ejemplo:

Me.TextBox1.CreateGraphics.DrawBezier(New Pen(Color.Orange, 2), _
New Point(20, 50), New Point(80, 10), New Point(120, 175), New Point(200, 200))

 

Bueno, son algunos puntos que se tocan en este artículo, para más detalle vea el artículo original.

Percy Reyes.

Publicado por Percy Reyes | con no comments

GDI+ (Parte II) : Creando objetos Graphics, Pen y Font, y manejando las estructuras Pens y Color

Dada la base introductoria acerca de GDI+( Vea CAPÍTULO I ), donde habíamos estudiado conceptos importantes relacionados a GDI+, empezaré a partir de este artículo a profundizar cada uno de los componentes de GDI+ (la tecnología contenida en .NET Frameworks con la que se pueden generar salidas gráficas, textuales y trabajo con mapas de bits e imágenes). Una de las cosas que habíamos mencionado es que toda la funcionalidad de GDI+ está en encapsulada en el assembly System.Drawing.dll. Por otra parte, todas las clases GDI+ classes se encuentran dentro de los namespaces System.Drawing, System.Drawing2D, System.Text, System.Design, System.Imaging, System.PrintingSystem.Internal . Ahora sí, empezemos detallando la clase Graphics.

LA  CLASE GRAPHICS  

Cuando usted se propone a dibujar una línea o cualquier forma manualmente, pues necesitará de un espacio donde hacerlo, como por ejemplo: un trozo de papel, una región de pared, o cualquier superficie de dibujo que esté en condiciones como para representar nuestras imágenes o creaciones. Pues bien, estas ideas llevémoslo a la práctica, es decir, a la parte programática. A ese trozo de papel, región de pared ... se llama lienzo, y en .NET  este lienzo está representado mediante la clase Graphics. Entonces, la clase Graphics viene a ser el lienzo donde expresaremos nuestro arte.

La clase Graphics es la base de la funcionalidad de GDI+, en otras palabras, es la clase que realmente dibuja líneas, curvas, figuras, imágenes y texto. Estas Clases cooperan entre ellas, es decir trabajan en conjunto, pero siempre al mando de nuestra majestad... la clase Graphics. Algo a resaltar acerca del clase Graphics es que éste carece de constructor público, negándonos de esta manera la posibilidad de instanciar un objeto Graphics con la palabra clave New,¿Qué pena verdad? pues no os preucupéis, ya que todo tiene su porqué, como veremos más adelante. Sigamos... Podemos crear nuestro objeto Graphics de diversas maneras, como por ejemplo:

'creamos un objeto Graphics en el formulario
Dim myLienzoForm As Graphics = Me.CreateGraphics

'creamos un objeto Graphics en un PictureBox
Dim myLienzoPictureBox As Graphics = PictureBox1.CreateGraphics

 'creamos un objeto Graphics en un control
Dim myLienzoControl As Graphics = Button1.CreateGraphics

Existe otra manera de crear un objeto Graphics, pero tiene que tener en cuenta algunos riesgos al hacerlo, ya que el repintado de la imagen puede verse afectado debido a la complejidad de esta.

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles

MyBase.Paint Dim myGraphics As Graphics = e.Graphics

End Sub


REFERENCIA Vea algo más acerca de la clase Graphics

NOTA: En algún momento deseaba que cuando se cargue el formulario se dibujara un gráfico, para la cual insertaba el código en el evento Load. Cuando corría la aplicación nunca observaba el gráfico dibujado, era claro que algo andaba mal, pues todo era incorrecto.  Ahora entiendo porque no era posible realizarlo. Pues me di cuenta que esto, era debido a que el evento Paint del formulario se levantaba después del evento Load, por eso no podía trabajar este código en este evento Load.  Es decir, el formulario se pintaba sin dibujar el gráfico. Para solucionar este problemilla, opté por escribir el código en el evento Paint del formulario, siempre que quisiese graficar cuando el formulario se cargue. Ejemplo:

Este código no mostrará resultado alguno.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles MyBase.Load

    Me.CreateGraphics.DrawLines(New Pen(Color.Blue, 4), New Point() {New Point(34, 56), New Point(74, 93), New Point(56, 12)})

End Sub

Este código dibuja dos segmentos conectados por la matriz de puntos (34,56), (74,93) y (56,12)

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _
    Handles MyBase.Paint

    Me.CreateGraphics.DrawLines(New Pen(Color.Blue, 4),    New  Point()
    {New Point(34, 56), New Point(74, 93), New Point(56, 12)})

End Sub

Ver artículo completo publicado en el www.elguille.info 

Percy Reyes.

Publicado por Percy Reyes | con no comments

Graficador de funciones en .NET (Parte II)

Después de haber explicado, en la parte I,  los fundamentos, pasamos al código.

Imports System.Drawing.Drawing2D
Imports System.Math

Public Class Form1
    Inherits System.Windows.Forms.Form
 <STAThread()> Shared Sub main()
        Try
            Application.Run(New Form1)
        Catch ex As Exception
            MsgBox("Cuidado :: " & ex.Message)
        End Try
    End Sub

    Public Shared a, b, c, d, e, f, g, h, i, j, k, m, constante As Single

    Public Function NetFuncion(ByVal X As Double) As Double
        'capturo los coeficientes...
        a = CType(Me.TextA.Text, Single)
        b = CType(Me.TextB.Text, Single)
        c = CType(Me.TextC.Text, Single)
        d = CType(Me.TextD.Text, Single)
        e = CType(Me.TextE.Text, Single)
        f = CType(Me.TextF.Text, Single)
        g = CType(Me.TextG.Text, Single)
        h = CType(Me.TextH.Text, Single)
        i = CType(Me.TextI.Text, Single)
        j = CType(Me.TextJ.Text, Single)
        constante = CType(Me.TextConstante.Text, Single)
        'reemplazo los coeficientes en la función...
        Return a * Pow(X, b) + c * Pow(X, d) + e * Cos(f * Pow(X, g)) + h * _
        Sin(i * Pow(X, j)) + constante
    End Function

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles MyBase.Load
        'manipulo algunas propiedades...
        Me.ControlBox = False
        Me.PictureBox1.BackColor = SystemColors.ControlLight
        Me.WindowState = FormWindowState.Maximized
        'defino la posición y tamno incial para el PictureBox1...
        Me.PictureBox1.Location = New Point(Me.Location.X + 40, Me.Location.Y + 20)
        Me.PictureBox1.Size = New Size(Me.ClientSize.Width - 200, Me.ClientSize.Height - 130)
        'genero aleatoriamente los coeficientes...
        Me.BtnGenCoef.PerformClick()
    End Sub

    'procedimiento para dibujar la cuadricula de fondo...
    Public Sub Cuadricula()
        'dibujamos la coordenada Y
        Me.PictureBox1.CreateGraphics.DrawLine(New Pen(Color.Red, 3), _
        New PointF(Me.PictureBox1.Width / 2, 0), _
        New PointF(Me.PictureBox1.Width / 2, Me.PictureBox1.Height))
        'dibujamos la coordenada X
        Me.PictureBox1.CreateGraphics.DrawLine(New Pen(Color.Red, 3), _
        New PointF(0, Me.PictureBox1.Height / 2), _
        New PointF(Me.PictureBox1.Width, Me.PictureBox1.Height / 2))
        'dibujo de toda cuadricula
        Dim NroLines As Integer = 0
        'lineas horizontales de la cuadrícula de fondo
        For NroLines = 0 To Me.PictureBox1.Height Step 10
            Me.PictureBox1.CreateGraphics.DrawLine(New Pen(SystemColors.Highlight, 1), _
            New Point(0, NroLines), New Point(Me.PictureBox1.Width, NroLines))
        Next
        'lineas verticales de la cuadrícula de fondo
        For NroLines = 0 To Me.PictureBox1.Width Step 10
            Me.PictureBox1.CreateGraphics.DrawLine(New Pen(SystemColors.Highlight, 1), _
            New Point(NroLines, 0), New Point(NroLines, Me.PictureBox1.Height))
        Next
    End Sub

    Public Function CalculateMaxAndMin(ByVal modo As Integer) As Single
        'algoritmo de optimización MÉTODO DE LA SECCIÓN DORADA
        'Sirve para hallar los punto máximo y mínimo de la función
        'que queremos graficar...
        Dim a, b, sol As Single
        'sol... viene a ser el valor X que se tomará como abscisa
        'para calcular el máximo y mínimo
        a = CType(TxtXini.Text, Single)
        b = CType(TxtXfin.Text, Single)
        Dim x1, x2, funx1, funx2 As Single
        Dim tol As Single = 0.00001
        Dim r As Single = 0.618
        Dim ErrorNet As Single
        ErrorNet = (1 - r) * (b - a)
        While (tol < ErrorNet)
            x1 = a + r * (b - a)
            x2 = b - r * (b - a) 

             If modo * NetFuncion(x1) > modo * NetFuncion(x2) Then
                a = x2
                ErrorNet = b - x1
                sol = x1
            Else
                b = x1
                ErrorNet = x1 - x2
                sol = x2 

          End If
        End While
        'finalmente devolvemos el valor de máximo o mínimo,
        'Nota: la variable "modo" determina de que si hallemos el máximo o el mínimo
        Return NetFuncion(sol)
    End Function

    Function Maximo() As Single
        Return CalculateMaxAndMin(1)
    End Function

    Function minimo() As Single
        Return CalculateMaxAndMin(-1)
    End Function

    'procedimiento para graficar la función...
    Public Sub GraficarFuncion()
        Cuadricula()
        Dim XMinUnidCartesianas, XMaxUnidCartesianas As Single
        Dim YminUnidCartesianas, YMaxUnidCartesianas As Single
        Dim XFinPixel, XIniPixel, YFinPixel, YIniPixel As Single
        Dim X = 0, Y = 0, Yp = 0, Xp As Single
        Dim X1, min, max As Single
        Dim c As Single = 0.0001
        XIniPixel = Me.PictureBox1.Location.X
        XFinPixel = XIniPixel + Me.PictureBox1.Size.Width
        YIniPixel = Me.PictureBox1.Location.Y
        YFinPixel = YIniPixel + Me.PictureBox1.Size.Height
        XMinUnidCartesianas = CType(TxtXini.Text, Single)
        XMaxUnidCartesianas = CType(TxtXfin.Text, Single)
        YminUnidCartesianas = minimo()
        YMaxUnidCartesianas = Maximo()
        Application.DoEvents() 

        Me.ProgressBar1.Maximum = Math.Abs(XMaxUnidCartesianas - XMinUnidCartesianas)
        Dim i As Single = 0
        For X1 = XMinUnidCartesianas To XMaxUnidCartesianas Step c
            If i <= Math.Abs(XMaxUnidCartesianas - XMinUnidCartesianas) Then
                Application.DoEvents()
                Me.ProgressBar1.Value = i
                i += c
            End If
            X = X1 : Y = NetFuncion(X)
            'tranformamos nuestras coordenadas cartesianas a píxeles
            'Xp = valor de la coordenada X en píxeles...
            Xp = XIniPixel + Pow(Pow(((XFinPixel - XIniPixel) * (X - XMinUnidCartesianas)) / _
            (XMaxUnidCartesianas - XMinUnidCartesianas), 2), 0.5)
            Yp = YIniPixel + Pow(Pow(((YFinPixel - YIniPixel) * (Y - YminUnidCartesianas)) / _
            (YMaxUnidCartesianas - YminUnidCartesianas), 2), 0.5)
            Dim PuntoInicial As PointF = New PointF(Xp - 40, Me.PictureBox1.Height - Yp + 10)

            X = X1 + c : Y = NetFuncion(X1 + c) 

             'Yp=valor de la coordenada Y en píxeles...
            Xp = XIniPixel + Pow(Pow(((XFinPixel - XIniPixel) * (X - XMinUnidCartesianas)) / _
            (XMaxUnidCartesianas - XMinUnidCartesianas), 2), 0.5)
            Yp = YIniPixel + Pow(Pow(((YFinPixel - YIniPixel) * (Y - YminUnidCartesianas)) / _
            (YMaxUnidCartesianas - YminUnidCartesianas), 2), 0.5)
             Dim PuntoFinal As PointF = New PointF(Xp - 40, Me.PictureBox1.Height - Yp + 10)

            Try
                Me.PictureBox1.CreateGraphics.DrawLine(New Pen(Color.Green, 3), _
                PuntoInicial, PuntoFinal)
            Catch ex As Exception
                Me.PictureBox1.CreateGraphics.DrawLine(New Pen(Color.Green, 3), 0, 0, 0, 0)
            End Try
        Next
        'dibujamos la cuadrícula...
        Cuadricula()
    End Sub

    Private Sub BtnLimpiar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles BtnLimpiar.Click
        Me.PictureBox1.Invalidate()
    End Sub

    Private Sub BtnGenCoef_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles BtnGenCoef.Click
        'genereamos valores inciales para los coeficientes...
        Randomize()
        Me.LabelTIEMPO.Visible = False
        Dim ran As New Random
        Me.TextA.Text = ran.Next(-2, 20)
        Me.TextB.Text = ran.Next(-2, 20)
        Me.TextC.Text = ran.Next(-2, 20)
        Me.TextD.Text = ran.Next(-2, 20)
        Me.TextE.Text = ran.Next(-2, 20)
        Me.TextF.Text = ran.Next(-2, 20)
        Me.TextG.Text = ran.Next(-2, 20)
        Me.TextH.Text = ran.Next(-2, 20)
        Me.TextI.Text = ran.Next(-2, 20)
        Me.TextJ.Text = ran.Next(-2, 20)
        Me.TextConstante.Text = ran.Next(-2, 20)
    End Sub

    Private Sub BtnSalir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles BtnSalir.Click
        Me.Close()
    End Sub

    Private Sub BtnGraficar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles BtnGraficar.Click
        Me.Label4.Visible = False
        Me.Timer1.Enabled = False
        Me.Timer2.Enabled = False
        'tiempo en que se empieza a graficar la función
        Dim TiempoInicial As Date = System.DateTime.Now
        'graficamos la función..
        GraficarFuncion()
        'tiempo en que se termina graficar la función
        Dim TiempoFinal As Date = System.DateTime.Now
        Me.LabelTIEMPO.Visible = True
        'calculamos el tiempo en segundos empleados para realizar la grafica...
        Me.LabelTIEMPO.Text = "Tiempo :: " & DateDiff(DateInterval.Second, TiempoInicial, _
        TiempoFinal).ToString & " Segundos."
        'mostramos los valores máximo y mínimo
        Me.TextBox1.Text = "MaximoY: " & Maximo()
        Me.TextBox2.Text = "MinimoY: " & minimo()
        Me.Timer1.Enabled = True
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles Timer1.Tick
        Me.Timer1.Enabled = False
        Me.Label4.Visible = False
        Me.Timer2.Enabled = True
    End Sub

    Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles Timer2.Tick
        Me.Timer2.Enabled = False
        Me.Label4.Visible = True
        Me.Timer1.Enabled = True
    End Sub
End Class

Nuevamente como siempre deseo que este trabajo haya sido de tu agrado y contribuido en mejorar tu experiencia como programador.

Artículo Original escrito para www.elguille.info

Percy Reyes.

Publicado por Percy Reyes | 7 comment(s)

Graficador de funciones en .NET

Este graficador de funciones nace de la idea o tal vez necesidad de presentarlo en un proyecto final de un curso en la universidad, mejor dicho en mi universidad (Universidad Nacional de Trujillo), aqui  en Perú. Sé que para mucho de ustedes amigos avanzados en .NET, se le debe hacer algo sencillo realizar lo que yo hice "heroícamente" (en aquellos tiempos) en una noche que nunca olvidaré, se suponía en ese momento de angustía y desesperación, en donde si este programa no corría entonces estaba muerto. Sucede que confiaba mucho en mí, y eso me animó echar siempre pa'lante (para adelante), al final todo salió muy bien y el graficador funcionó correctamente...jejeje..Vale la pena resaltar que el graficador que se presentó en el proyecto lo desarrollé en c++, ya que no es tan sencillo en este lenguaje...., felizmente como buen programador tengo las ideas bien puestas y será el fruto del código binario lo que cosecharé, con el pasar del tiempo, y no calificaciones , es decir, en la programación ó  eres un uno ó eres un cero, tú eliges.

Inevitablemente, la vida de un programador se caracteriza por su constante aprendizaje, un programador que desee estar a la par y siempre al día sufrirá de la "maldición eterna" del estudio. La situación real es que, el área de la informática avanza a tal velocidad que tomar un descanso de un par de semanas pueden significar que ahora estes al final de la fila, cuando, tal vez, una vez estuviste al principio. Es debido a esto que debemos buscar ciertos patrones de comportamiento positivos para realizar prácticas de programación que nos ayuden a desarrollar software de una manera eficiente y muy rápida.

Aprendí a programar a los 16 años (empecé con PASCAL), actualmente vivo muy empeñoso con .NET, al principio fue una cosa rara todo esto de la programación pero todo cambió, ahora es algo muy común para mi. Con esto quiero decirte que, una vez  que aprendes a programar es siempre cuestión de como saber traducir tus ideas al dialecto programático en el cual estés interesado. Se trata simplemente de sentarte frente a tu PC y hablarle en el lenguaje  que esta entienda, es más, tú puedes elegir en  que dialecto o lenguaje hablarle y ordenarle lo que  desees, piensa que el ordenador es tu amigo y a la vez tu empleado..jejejeje.... 

Esta vez no quiero demostrate un descubrimiento en la programación gráfica o algún aspecto marcianamente complejo, sino más bien, quiero mostrarte sencillamente la manera como desarrollé un graficador de funciones en VB .net, el cual es interesante debido a la lógica que utilicé. Si sabes alguna manera distinta de desarrollar un graficador pues escríbeme al correo. Además, debo decirte que este documento recoge ideas, estilos y maneras de hacer fáciles las cosas "complejas" de la programación, la cual comparto con ustedes  de tal forma que puedan aprovecharlos. Quiero dejar constancia que parte del contenido de esta página fue tomada de un curso de programación gráfica, mejor dicho tan sólo la teoría, ya que el graficador lo implementé yo, tomando sólo algunas pautas que este curso me brindaba. Bueno, para aprender a realizar prácticas de programación gráfica, debemos empezar por saber lo más básico, cuya información al respecto sigue a continuación.

Trazar Ecuaciones

Para comenzar, veamos un ejemplo práctico del uso de gráficos: trazar la gráfica de una ecuación. En este capítulo trazaremos la ecuación: y = 3x2 - 6. Como ya sabemos, esta ecuación describe una parábola cóncava (hacia "arriba") - en el sentido positivo por el eje-Y. Nosotros, como matemáticos, trazamos tal gráfica tomando ciertos valores de x para calcular valores de y y así crear coordenadas por donde pasará la gráfica. Al ser humanos, no nos gusta tomar todos los posibles valores, por lo que creamos una tabla de valores calculando algunas coordenadas, hasta que tengamos una idea de dónde situar la gráfica. En nuestra ecuación, sabemos de antemano que se trata de una parábola, por lo que ya conocemos su forma y estructura. En papel, aproximamos el trazado a la gráfica real, ya que no nos hace falta tanta precisión; o sea, lo hacemos a ojo de buen cubero. Sin embargo, esto no es posible al crear la gráfica en pantalla: necesitamos ser precisos.

Cambio de Coordenadas   

La ventaja que tenemos es que el ordenador no se "cansará" al calcular todos los valores que requerimos, por lo que no tendremos problemas de precisión. Por otro lado, estamos intentado representar una imagen de dimensiones infinitas - el plano cartesiano, debido a los valores de x que son infinitos, en un área de dimensiones finitas - la pantalla. Por lo tanto, debemos representar la gráfica ajustándonos a las dimensiones de nuestra pantalla. Las dimensiones de la imagen equivalen a la resolución gráfica establecida. Para este ejemplo, usaremos una resolución de 800x600.

Ahora tenemos que pensar qué representa cada píxel que activemos - demos color. Si establecemos que cada píxel equivale a una unidad matemática, entonces no obtendremos una imagen presentable. Hay que tener en cuenta que las unidades matemáticas no tienen por qué ser valores enteros, mientras que los píxeles sí deben serlos. Lo que tenemos que hacer es decidir los valores mínimos y máximos a usarse en la ecuación. Digamos que queremos ver parte de la gráfica usando los valores de x : [-3, +3]; o sea, xui = -3 y xuf = 3, los cuales representan los valores mínimos y máximos de las unidades del plano cartesiano, respectivamente. Aún así, no podemos usar todos los valores en este conjunto, ya que serían infinitos. Como ya sabemos, no podemos representar valores infinitos en un sistema de valores finitos (limitados). Tenemos que repartir estos valores cartesianos de entre los posibles valores de la pantalla del mismo eje X; es decir, tenemos que conseguir cambiar el intervalo [-3, +3] al de [0, 799]. Los valores iniciales y finales son fáciles de averiguar: xui = -3 => 0 y xuf = 3 => 799. Los demás valores deberán ser calculados:
Primeramente, debemos cambiar la escala o longitud: 6 (=3-(-3)) unidades cartesianas a 800 píxeles (el número de columnas); esto implica que existen 6/800 unidades cartesianas por cada píxel, que es lo mismo que decir: 0,0075 unidades/píxel. Dicho de otro modo, cada píxel representará 0,0075 unidades cartesianas. Miremos unos cuantos valores, para ilustrar este concepto:

Valores de X
Unidades Cartesianas
Píxeles
-3,0000
0
-2,9925
1
-2,9850
2
-2,9775
3
.
.
.
.
.
.
2,9700
796
2,9775
797
2,9850
798
2,9925
799


También podemos establecer la relación realizando la operación inversa: 800/6 = 133,3333 píxeles/unidad. Aquí podemos ver que sería algo difícil representar 133,3333 píxeles, ya que los píxeles son siempre enteros. Esto implica que obtendremos errores al aproximarnos a un número entero; en este caso, 133 (~133,3333).

Cual sea la relación, podemos averiguar un píxel determinado a partir de una coordenada cartesiana determinada, y viceversa. Por ejemplo, si tenemos la coordenada-X de un píxel, xp = 345, para poder averiguar el valor de x en unidades cartesianas, realizamos la siguiente operación:

 6 unidades         |xu - xui| unidades
-------------  =  ---------------------- =>
 800 píxeles        |345 - xpi| píxeles

|345 - 0| píxeles * 0,0075 unidades/píxel = |x - (-3)| unidades =>

x = -0,4125 unidades.

Por otro lado, podemos averiguar el píxel correspondiente a la coordenada-X, xu = -2,0000, aplicando la simple regla de tres:

 800 píxeles          |xp - xpi| píxeles
-------------  = -------------------------- =>
 6 unidades        |-2,0000 - xui| unidades

1,000 unidad * 133,3333 píxeles/unidad = |xp - 0| píxeles =>

x = 133,3333 píxeles => x = 133 píxeles.

Del mismo modo, tenemos que averiguar los valores de y en unidades cartesianas correspondientes con los valores en píxeles. El número de filas es 600 píxeles, según nuestra resolución que hemos elegido. Ya que los valores del eje-Y son imaginarios, éstos pueden ser calculados. Por esta razón, el conjunto de valores puede ser ajustado según los valores inicial y final del eje-X. Con xui = -3, obtenemos yu = 3 (xui)2 - 6 => yu = 21. Con xuf = 3, obtenemos yu = 21. Ahora averiguaremos la coordenada del valor mínimo de yu de la curva con la siguiente fórmula: 6xu = 0 => xu = 0, y por tanto, yu = -6.  La fórmula usada proviene de la derivada de nuestra ecuación: yu = 3 (xu)2 - 6, para averiguar el punto crítico. Ahora tenemos que los valores de y se encuentran entre [-6, +21]; esto es, yui = -6 e yuf = +21. Por lo tanto, necesitamos realizar otro cambio de escala: 27 (=21-(-6)) unidades cartesianas a 600 píxeles (el número de filas). Esto quiere decirse que tenemos 27/600 = 0,0450 unidades/píxel. Veamos unos cuantos valores:

Valores de Y

Unidades Cartesianas

Píxeles

-6,0000

0

-5,9550

1

-5,9100

2

-5,8650

3

.
.
.

.
.
.

20,8200

596

20,8650

597

20,9100

598

20,9550

599

Calculemos el píxel que corresponda al valor en unidades cartesianas de yu = 3 (-2,000)2 - 6 => yu = 6,000. Nuevamente se trata de aplicar la regla de tres con la información que tenemos:

 
600 píxeles           |yp - ypi| píxeles
-------------  = -------------------------- =>
 27 unidades        |6,0000 - yui| unidades

|6,0000 - (-6)| unidades * 22,2222 píxeles/unidad = |yp - 0| píxeles =>

y = 266,6666 píxeles => y = 267 píxeles.

Hasta aquí es la teoría, ahora, les muestro el código del ejemplo que implementé en Microsoft® Visual Basic .NET®. Pero antes debo decirle que la cuestión de resolución gráfica, los límites de la función a graficar, los puntos máximos y mínimos, y otros detalles, fueron manejadas de acuerdo a mi estilo personal. Para los curiosos, este graficador se basa en una resolución gráfica de 1024x768 píxeles, te comunico esto para evitarte molestias al momento de probarlo.

Al revisar el código notarás que existe un algoritmo que implementé para calcular los puntos máximo y mínimo de la función, si quieres saber de se trata este algoritmo entonces te recomiendo buscar en la web toda información con respecto a optimización de funciones, en especial "Método de la Sección Dorada", la cual uso para hallar estos puntos... bueno esto yo lo aprendí en la universidad.

Cuando el programa empieza graficar la función, lo hace de una manera progresiva y dinámica, empleando para esto un ProgressBar para ir mostrando al usuario el avance del trabajo. ¿...interesante, verdad...?.

....luego observamos que la construcción de la gráfica está yendo por bueno camino, siguiendo el avance de toda la gráfica  mediante el ProgressBar. De esta manera, hacemos el trabajo algo más divertido. 

Finalmente, observamos que la construcción ha concluido con éxito, nuestra función ha sido graficada. También se puede ver que al final  de este proceso se muestra un mensaje parpadeante avisándonos que todo  ha salido bien, además visualizaremos los puntos máximo y mínimo de la función. Un detalle importante es que podemos medir el tiempo empleado para realizar la gráfica. Bueno hasta aquí ha sido todo  el "chiste"....

A continuación sigue (en la parte II) el código en Microsoft® Visual Basic .NET®.

Percy Reyes.

Publicado por Percy Reyes | 10 comment(s)

GDI+ : Aplicaciones independientes del dispositivo (Parte I)

¿Qué es...? ¿Cómo funciona...? ¿Aplicaciones independientes del dispositivo...? Si alguna vez te has planteado estas preguntas, seguramente estabas deseando que alguien te dé una explicación sencilla y precisa. Pensando en esto es que me animé a realizar este trabajo para tratar de ayudar a toda la comunidad desarrolladora de aplicaciones .NET. Bueno, empecemos.... pero antes debo anticiparles o prevenirles que en este capítulo sólo explicaré conceptos generales, es por eso que algunos ejemplos que incluyo no están detallados o explicados completamente. El objetivo es que te formes una idea o captes conceptos importantes con respecto a GUI+. Más adelante en otros capítulos se explicarán temas interesantes al respecto, pero por ahora basta con esto. Debo decirle que este capítulo viene a formar la primera parte de todo un manual que se irá explicando por capítulos. Al final cuando termine de publicar todo los capítulos que formará parte de este manual agregaré una página dónde estarán todos los links respectivos de los temas. 

Ahora sí empecemos. GDI+ es una interfaz de programación de aplicaciones (API) que se expone a través de un conjunto de clases implementadas como código administrado. GDI+ viene a ser la interfaz de dispositivo gráfico que se encarga de mostrar información en pantallas e impresoras, la cual permite a nosotros, como programadores de aplicaciones, mostrar información en una pantalla o impresora sin tener que preocuparnos por los detalles de un dispositivo de presentación específico, es decir, cuando desarrollemos aplicaciones usando los métodos suministrados por las clases de GDI+ no tendremos porque preocuparnos por manejar cuestiones de hardware gráfico, ya que todo este trabajo lo hará los métodos GDI+ , llamando a los controladores de dispositivo específicos, de esta manera GDI+ aísla o separa a la aplicación del hardware gráfico, y este aislamiento es el que permite a nosotros, los programadores, crear aplicaciones independientes del dispositivo. Ahora podemos decir con seguridad que GDI+ es una interfaz de dispositivo gráfico que permite a los programadores escribir aplicaciones independientes del dispositivo.

Todo el código que  se encuentran más adelante se basa en System.Drawing y System.Drawing.Drawing2D, la explicación es que las clases que producen gráficos vectoriales en  Visual Basic .NET están contenidas en estos  espacios de nombres.

Imports System.Drawing
Imports System.Drawing.Drawing2D

La  estructura  de la interfaz de clases administradas en GDI+  incluye :

Clases: La clase Graphics es la base de la funcionalidad de GDI+; es la clase que realmente dibuja líneas, curvas, figuras, imágenes y texto. Estas Clases cooperan entre ellas, es decir trabajan en conjunto, pero siempre al mando de nuestra majestad... la clase Graphics.Por ejemplo:

  • El método Graphics.DrawLine recibe un objeto Pen, que contiene los atributos (color, ancho, estilo de guión, etc.) de la línea que se va a dibujar.

               PictureBox1.CreateGraphics.DrawLine(ObjetoPen, MiPuntoIncial, MiPuntoFinal)

El código anterior explica lo siguiente: El  objeto PictureBox1 mediante el método CreateGraphics se dá la potestad así mismo de ser el lienzo donde  mostraremos todo lo que vayamos dibujando, es decir se dibujará una línea sobre el PictureBox1 mediante el método DrawLine. En lugar de  Picturebox1 puede usarse Me para dibujarse sobre el formulario.            

  • El método Graphics.FillElipse  puede recibir un puntero a un objeto LinearGradientBrush, que trabaja con el objeto Graphics para rellenar un rectángulo con un color que cambia gradualmente.
'Dibuja un círculo con un relleno de color gold
Me.CreateGraphics.FillEllipse(Brushes.Gold, New Rectangle(New Point(200, 200), New Size(500, 200)))

Entre otros tenemos por ejemplo a los objetos Font y StringFormat, las cuales influyen en el modo en que el objeto Graphics dibuja texto.Un objeto Matrix almacena y manipula la transformación de coordenadas universales de un objeto Graphics, que se utiliza para girar, ajustar la escala y voltear imágenes. 

Dim Matriz As Matrix = New Matrix(System.Math.Sin(45.0R * 3.1416 / 180), _
System.Math.Cos(45.0R * 3.1416 / 180), -System.Math.Cos(45.0R * 3.1416 / 180), _
System.Math.Sin(45.0R * 3.1416 / 180), 0.0F, 0.0F)

Enumeraciones: GDI+ define varias enumeraciones, que son colecciones de constantes relacionadas.Por ejemplo,
la enumeración pens contiene los elementos Blue, Red, Green y otros, que especifican colores que pueden utilizarse
para definir el color del lápiz.

Me.CreateGraphics.DrawLines(Pens.Blue, New Point() _
{New Point(100, 50), New Point(150, 75), New Point(200, 15), New Point(200, 168)})

Estructuras:  GDI+ proporciona varias estructuras (por ejemplo, Rectangle, Point y Size) para organizar datos de gráficos. Además, algunas clases sirven principalmente como tipos de datos estructurados. Por ejemplo, la clase BitmapData es una clase auxiliar de la clase Bitmap, y la clase PathData es una clase auxiliar de la clase GraphicsPath.  

'rellena un cuadrado
PictureBox1.CreateGraphics.FillRectangle(New SolidBrush(Color.BurlyWood), _
New Rectangle(New Point(10, 10), New Size(300, 100)))
 

Los servicios de GDI+ que se exponen a través de un conjunto de clases administradas, se agrupan en tres categorías:

 Gráficos vectoriales 2D: Se refiere al dibujo de líneas, curvas y figuras( tipos primitivos ) que se especifican mediante conjuntos de puntos en un sistema de coordenadas. Por ejemplo:

Una línea recta puede especificarse mediante sus dos extremos: 

         ' Especificamos el lapiz con el que dibujaremos la recta
         Dim Lapiz As Pen = New Pen(Color.Blue) 'definimoa además el color
         ' Creamos los puntos o extremos de la recta
         Dim PuntoIncial As Point = New Point(10, 10)
         Dim PuntoFinal As Point = New Point(300, 300)
         'Finalmente dibujamos la línea...sobre un PictureBox
         PictureBox1.CreateGraphics.DrawLine(Lapiz, PuntoIncial, PuntoFinal)

Un rectángulo puede especificarse mediante un lápiz con el que dibujaremos, un punto que indique la ubicación del borde superior izquierdo y un par de números que indiquen el ancho y el alto. 

'Creamos el lápiz de color RoyalBlue y de tamaño 4
Dim Lapiz As New Pen(Color.RoyalBlue, 4)
Dim PuntoBordeSuperiorIzquierdo As Point = New Point(50, 50)  Dim Ancho As Integer = 100
Dim Alto As Integer = 179
 'Dibujamos sobre el formulario
Me.CreateGraphics.DrawRectangle(Lapiz, New Rectangle(PuntoBordeSuperiorIzquierdo, New Size(Ancho, Alto)))

Un trazado simple puede especificarse mediante una matriz de puntos que se van a conectar mediante líneas rectas.

Me.PictureBox1.CreateGraphics.DrawPolygon(Pens.Red, New Point() {New Point(150, 150), _
New Point(100, 100), New Point(150, 50), New Point(250, 150), New Point(300, 100), New Point(250, 50)}

Una curva spline de Bézier es una curva sofisticada, especificada por cuatro puntos de control.

Me.PictureBox1.CreateGraphics.DrawBezier(New Pen(Color.Red, 2), New Point(10, 30), _
New Point(10, 250), New Point(140, 50), New Point(300, 300))

Imágenes:  Existen tipos de imágenes que no se pueden o son muy difíciles de mostrar con las técnicas de gráficos vectoriales. Por ejemplo:

  • Las imágenes de los botones de la barra de herramientas y las imágenes que aparecen en forma de iconos serían difíciles de especificar en forma de colecciones de líneas y curvas.
  •  Una fotografía digital de alta resolución de un estadio de béisbol abarrotado sería aún más difícil de crear con las técnicas vectoriales.

    El detalle radica en que las imágenes de este tipo se almacenan como mapas de bits, matrices de números que representan los colores de puntos individuales de la pantalla.Para solucionar este detalle, GDI+ proporciona la clase Bitmap para mostrar, manipular y guardar mapas de bits.

Tipografía: Se ocupa de la presentación de texto en diversidad de fuentes, tamaños y estilos. GDI+ proporciona una gran compatibilidad para esta tarea tan compleja. Una de las nuevas características de GDI+ es la función de alisado subpíxel, que proporciona una apariencia más regular al texto que se muestra en una pantalla LCD.

Artículo Original escrito para el www.elGuillle.info

Publicado por Percy Reyes | 3 comment(s)

Programa de certificación Microsoft IT

Hace mucho tiempo había hecho un resumen de todos los exámenes que se deben aprobar para obtener cada una de las certificaciones. Esta vez he decidido compartirlo con ustedes y espero les sea de utilidad.
 
Microsoft Certified Technology Specialist (MCTS)
  • MCTS: .NET Framework 2.0 Windows Applications
       -Exam 70-536: TS: Microsoft .NET Framework 2.0 - Application Development Foundation
       -Exam 70-526: TS: Microsoft .NET Framework 2.0 - Windows-Based Client Development
  • MCTS: .NET Framework 2.0 Web Applications
     -Exam 70–536: TS: Microsoft .NET Framework 2.0 - Application Development  Foundation
     -Exam 70–528: TS: Microsoft .NET Framework 2.0 - Web-Based Client Development
  • MCTS: .NET Framework 2.0 Distributed Applications
      -Exam 70–536: TS: Microsoft .NET Framework 2.0 - Application Development Foundation
      -Exam 70–529: TS: Microsoft .NET Framework 2.0 - Distributed Application Development
  • MCTS: SQL Server 2005
    - Exam 70–431: TS: Microsoft SQL Server 2005 - Implementation and Maintenance
  • MCTS: BizTalk Server 2006
      - Exam 70–235: TS: Developing Business Process and Integration Solutions Using BizTalk Server 2006
  • MCTS: SQL Server 2005 Business Intelligence 
     

MCITP (Microsoft Certified IT Professional)

IT Professional: Database Developer (en inglés)
IT Professional: Database Administrator (en inglés)
IT Professional: Business Intelligence Developer (en inglés)

Certificación MCPD (Microsoft Certified Professional Developer)

MCPD: Web Developer

Si aún no tienes la certificación MCAD:

  • Exam 70–528: TS: Microsoft .NET Framework 2.0 - Web-Based Client Development
  • Exam 70–547: PRO: Designing and Developing Web Applications by Using the Microsoft .NET Framework

Si eres MCAD, 

  • Prerequisito:  Exam 70–551
  • Exam 70-547: PRO: Designing and Developing Web Applications by Using the Microsoft .NET Framework

Si has aprobado:  Exam 70–552 Entonces te basta rendir estos exámenes:

 

  • Exam 70–528: TS: Microsoft .NET Framework 2.0 - Web-Based Client Development
  • Exam 70–547: PRO: Designing and Developing Web Applications by Using the Microsoft .NET Framework

  Si eres MCSD:

Prerequisito: Exam 70–553

 

Exam 70–547: PRO: Designing and Developing Web Applications by Using the Microsoft .NET Framework

 MCPD: Windows Developer

Prerequisito:   MCTS: .NET Framework 2.0 Windows Applications

Exam 70–548:PRO: Designing and Developing Windows Applications by Using the Microsoft .NET Framework

 Si eres MCAD,

Prerequisito:  Exam 70–552

 

    • Exam 70-526: TS: Microsoft .NET Framework 2.0 - Windows-Based Client Development
    • Exam 70-548: PRO: Designing and Developing Windows Applications by Using the Microsoft .NET Framework

Si eres MCSD:

  • Prerequisito: Exam 70–553:
  • Exam 70-548: PRO: Designing and Developing Windows Applications by Using the Microsoft .NET Framework

uff... ya me cansé  XD. ;).

Más: http://www.microsoft.com/spain/formacion/mcp/default.mspx
Publicado por Percy Reyes | 4 comment(s)

Usando T-SQL para producir HTML

Un amigo me consultó lo siguiente ¿Cómo hago para producir HTML usando T-SQL?, para ayudarle hice un ejemplo, y creí conveniente compartirlo con este post. Esta vez vamos a ver un ejemplo sencillo al respecto. Digamos que tenemos el siguiente código en T-SQL.

USE Northwind
GO
SELECT P.[ProductID],
P.[ProductName],
C.[CategoryName]
FROM Products P
INNER JOIN Categories C
ON P.CategoryID = C.CategoryID

el resultado será mostrado en una cuadrícula :

Para producir este resultado en un formato HTML, lo único que necesitamos es tabular este resultado usando etiquetas HTML para llenar el result set en una tabla. Es decir, encerrar el texto plano produciendo finalmente una tabla con data.

El resultado será código HTML. 

Click Aquí para ver la imagen completa

Podemos usar SQLCLR para guardar este código en un archivo HTML, e inmediatamente abrirlo usando IExplorer.

También podemos producir resultados en formato HTML, usando el procedimiento almacenado sp_makewebtask. Este procedimiento crea un SQL Server job que produce HTML de los datos almacenados en un SQL Server database. No detallaré acerca de esta característica debido a que será eliminado en las próximas versiones de SQL Server (además de ser riesgoso), sin embargo puede consultar el siguiente recurso. Se recomienda evitar el uso de esta característica, y en su lugar use Reporting Services. Espero sirva a los interesados.

Publicado por Percy Reyes | 1 comment(s)

Solucionando problemas entre TABLESAMPLE, PIVOT, UNPIVOT y REVERT, y los Niveles de Compatibilidad Inferiores a 90

Cuando se trabaje con la cláusula TABLESAMPLE, PIVOT, UNPIVOT y REVERT para programar ciertos scripts que manipulen base de datos con niveles de compatibilidad 70 (SQL Server 7.0) y 80 (SQL Server 2000) debe tenerse en cuenta que esta cláusula es exclusiva del nivel de compatibilidad 90 (SQL Server 2005) y por lo tanto al usarla el motor de SQL Server 2005 nos indicará un error.

Cada versión de SQL Server introduce palabras claves reconocidas por el motor de ejecución, dado esto, las palabras claves permanecerán reservadas para esa versión. Ejemplo, la palabra clave TABLESAMPLE, se introdujo en el nivel de compatibilidad 90, por lo tanto está palabra no será reconocida cuando se trabaje con base de datos cuyos niveles de compatibilidad sean 70 ó 80.

Por ejemplo, se me ocurrió usar TABLESAMPLE para consultar data de la base de datos Northwind (por defecto, nivel de compatibilidad 80), veámos :

SELECT CustomerID, CompanyName, ContactName
FROM dbo.Customers
TABLESAMPLE (15 PERCENT)

Al correr este código, el  SQL server 2005 Database Engine me dice que hay un error.

Mens. 156, Nivel 15, Estado 1, Línea 3
Sintaxis incorrecta cerca de la palabra clave 'PERCENT'.

Bien, me puse a pensar, cual es la causa del error, obviamente que la sintaxis está correcta, pero ¿Qué es?.. en fin, ¿Cómo solucionar esto?, sin haber leído alguna documentación al respecto, decidí cambiar el nivel de compatibilidad de la base de datos, pero antes me aseguré cual era el nivel de compatibilidad de la base de datos(sólo para recontra asegurarme!.):

SELECT [name], [compatibility_level] FROM sys.databases
WHERE [name]='Northwind'

name                     compatibility_level
---------------------   ------------------
Northwind               80

(1 filas afectadas)

Ahora sí, migremos a otro nivel!.

EXEC sp_dbcmptlevel 'Northwind', '90';

El motor de ejecución de SQL server 2005 nos confirma el cambio de compatibilidad ha sido exitosa:

Ejecución de DBCC completada. Si hay mensajes de error, consulte al administrador del sistema.

Hasta este momento seguía suponiendo que el problema debería ser por cuestiones de compatibilidad(créanme, es sentido común!!!). En fin, ahora ya está listo!, la base de datos ya debe trabajar con la cláusula TABLESAMPLE. Ahora comprobemos.

SELECT CustomerID, CompanyName, ContactName
FROM dbo.Customers
TABLESAMPLE (15 PERCENT)

 

Efectivamente era porque la base de datos Northwind no tenía nivel de compatibilidad 90, sino 80. Luego de haber solucionado este problema, decidí revisar al respecto en la ayuda online de SQL Server 2005, no encontré específicamente esta solución, pero sí un párrafo que me da la razón acerca del porqué de este error.

En un nivel de compatibilidad dado, las palabras clave reservadas incluyen todas las palabras clave introducidas en ese nivel o por debajo. Por ejemplo, para las aplicaciones en el nivel 90, todas las palabras clave mostradas en la tabla anterior son reservadas. En los niveles de compatibilidad inferiores, las palabras del nivel 90 siguen siendo nombres de objeto válidos, pero las características de idioma del nivel 90 correspondientes a esas palabras clave no están disponibles.

El mismo tipo de problema también surgirá cuando se intente trabajar con PIVOT, UNPIVOT, REVERT, así que en primer lugar no te olvides de cambiar el nivel de compatibilidad. Aquí dejo el listado de palabras claves para cada nivel de compatibilidad.

Con esto espero ahorrarte un dolor de cabeza :). Dejo algunos recursos que pueden servirte: Limitar los conjuntos de resultados con TABLESAMPLE , SQL Server 2005 TABLESAMPLE clause .

Percy Reyes.

Publicado por Percy Reyes | 4 comment(s)

Recompilacion a nivel de sentencia en SQL Server 2005

Con la llegada de SQL Server 2005 hemos podido ver muchas mejoras y grandes cambios beneficiosos para developers y DBAs. Uno de estos grandes cambios es la manera en que las consultas son compiladas. En este post vamos hablar especificamente acerca de la recompilación a nivel de sentencia, una nueva característica introducida en SQL Server 2005. Todo empezo en SQL Server 2000 con una gran mejora en su arquitectura de consulta manejando dos planes: un plan de compilación (estructura de data de solamente lectura usado por cualquier número de usuarios, y que no existe más que dos copias, una copia para ejecuciones en serie y otra para ejecuciones paralelas), y un plan de ejecución que crea una estructura de data para cada usuario que actualmente esté ejecutando la consulta.

Hasta aquí todo bien, ya que esta arquitectura es beneficiosa cuando se trabaja con stored procedures, funciones, consultas dinámicas, etc, sin embargo, hay un problema común cuando se trabaja con stored procedures. Este problema es la necesidad de recompilación de todo el stored procedure luego haberse realizados pequeños cambios en el esquema y algunas opciones SET. La cuestión es que una vez realizado los cambios por más mínimo que sea, esto llevará consigo, como ya dije, una recompilación completa de todo el procedimiento almacenado, y peor aún si el stored procedure es grande, lo cual era muy costoso; este tipo de recompilación a nivel de módulo sucede en SQL Server 2000. En SQL Server 2005 ya no pasa lo mismo gracias a la nueva característica denominada recompilación a nivel de sentencia (Statement-Level Recompile), es decir, después de realizar cambios, ya sea a nivel de esquema o a nivel de opciones SET sólo se recompilará las sentencias modificadas.

Un artículo interesante al respecto es Statement-Level Recompile donde se detalla con algunos ejemplos.

Percy Reyes.

Publicado por Percy Reyes | con no comments

Salvando y ejecutando scripts con SQL Server Express Utility

Una herramienta bastante útil para interactuar con SQL Server 2005 es SQL Server Express Utility (SSEUtil), cuyas características son las siguientes:

  • Connect to the main instance or user-instance of SQL Server.
  • Create/Attach/Detach/List databases on the server.
  • Upgrade database files to match the version of the server.
  • Execute SQL statements via the console (similar to SQLCMD) or the console window (UI).
  • Retrieve the version of SQL Server running.
  • Enable/Disable trace flags (e.g. to trace SQL statements sent to the server by any client app)
  • List the instances of SQL Server on the local machine or on remote machines.
  • Checkpoint and shrink a database
  • Measure the performance of executing specific queries using the timer function (console mode).
  • Create and playback lists of SQL commands to be executed by the server.
  • Log all input/output.

Podemos descargarla desde aquí, y luego de instalarla tendremos el archivo ReadMe.htm para revisarla donde hay muchos ejemplos útiles.

SSEUtil funciona en dos modos: normal (soporta TQL Commands, ejecutados directamente sobre el servdidor) y extendido (soporta comandos extendidos que son interpretados primero por la consola). Los comandos extendidos son precedidos con un caracter  "!".

El modo normal de esta herramienta  trabaja con los siguientes comandos y opciones:

Comandos ::

  • -a[ttach] <dbpath> [<dbname>] :   Attach a database file to the server using the name if specified.
  • -create <dbpath>|name=<dbname> [<dbname>] : Create a new database given the database path or name.
  • -l[ist] :  Lists all databases on the server.
  • -d[etach] <dbpathStar>|name=<dbname> : Detaches database(s) by path or name.
  • -u[pgrade] <dbpath>|<directory> : Upgrades an individual database file or all database files in a folder.
  • -t[race] +|-[<number>] : Enables or disables the specified trace number for all client connections. Exclude number to trace SQL commands. Output written to the server log.
  • -childlist : Lists the child (user) instances of SQL Server.
  • -c[onsole] : Console mode. Allows user to type SQL statements to run on the server.
  • -consolewnd : Launches the interactive console window.
  • -run <filepath> [<var1>=<val1>[,...]] :  Runs a command file (SQL or extended commands) with the variables provided.
  • -version : Displays the version reported by SQL Server.
  • -listsrv [remote] :Lists the local or remote instances of SQL Server.
  • -shrink <dbpath>|name=<dbname> : Shrinks the given database and runs checkpoint.

Opciones ::

  • -m[ain] : Use the main instance. (Default is to use the child instance.)
  • -child [<username>] : Connect to child instance for the current or specified user.
  • -s[erver] <server>[\<instance>][,<port>] : Specify the server, instance name and/or port to connect to.   e.g. -s .\SQLEXPRESS will connect to SSE on the local machine.
  • -user <username> : Specify the user name to connect with.
  • -pwd <password> | -pwd?  : Specify the password to connect with, or prompt for it.   e.g. -s mysrv -user sa -pwd? will prompt for a password.
  • -timeout <seconds> : Specify the connection timeout in seconds. 0 for infinite.
  • -cmdtimeout <seconds> : Specify the command timeout in seconds. 0 for infinite.
  • -log <logfile> : Write all program input/output to the specified log file.

El modo extendido, es decir, modo consola, a parte de soportar los TSQL en modo normal, también trabaja con los siguientes comandos extendidos:

  • !attach <dbpath> [<dbname>] : Attaches a database file to the server using the name if specified.
  • !create <dbpath>|name=<dbname> [<dbname>] : Creates a new database given the database path or name.
  • !detach <dbpath[*  ]>|name=<dbname> : Detaches database(s) by path or name.
  • !list : Lists all databases on the server.
  • !timer : Turns the timer on/off. Will report the execution time of each command.
  • !commandTimeout timeout_in_seconds : Sets the command timeout. 0 sets the timeout to unlimited.
  • !run commandfile [var1=val1,...] : Run the given command file optionally passing in variable declarations.
  • !consolewnd : Shows the interactive console window.
  • !history show [count] : Shows all command history or the last 'count' commands.
  • !history save filepath : Saves the command history to a file for later playback (see the 'run' command).
  • !history clear : Clears the command history.
  • !logopen filepath | !logclose : Opens/closes log file. All input/output is written to the log.

Unas de las funcionalidades de esta herramienta que más me gustó es poder salvar un script y reutilizarlo, para esto adjunté una base de datos al servidor SQL Express de una manera realmente sencilla y muy fácil.

C:\SSEUtil.exe -a C:\DB\PUBS.mdf

Ahora que tengo la base de datos adjuntada, paso a hacer una consulta de prueba, para esto primero cambio el modo normal a modo consola.

C:\SSEUtilexe -c

Console mode. Type 'help' for more information.

1> use "C:\DB\PUBS.mdf"

2> SELECT * FROM jobs ORDER BY job_desc,min_lvl

3> GO

Podemos ver los resultados de la consulta:

Bien hasta todo muy fácil, y lo que viene es aún más fácil!!! :). A continuación pasaremos a guardar la consulta anterior, para esto, escribimos lo siguiente y le damos enter:

1>!history save "C:\Comandos.txt"

Ahora ya tenemos el script salvado!. Pasamos a ejecutar dicho script nuevamente usando el modo consola de SSEUtil. Para esto, nuevamente, escribimos y le damos un enter!:

1> !run "C:\Comandos.txt"

Veremos que el script a sido leído y ejecuta correctamente. Esto es sólo una muestra de cómo podemos explotar esta herramienta cuando estamos usando SQL Server 2005 Express Edition, SQL Server 2000 y versiones anteriores.  Espero sea de utilidad a los interesados!.

Percy Reyes.

Publicado por Percy Reyes | 4 comment(s)

Explorando las Funciones de Ranking en SQL Server 2005

Ya ha pasado casi un anio y medio desde el lanzamiento de SQL Server 2005, trayendo consigo un conjunto de nuevas caracteristicas (tanto para DBAs, desarrolladores y gente experta en BI) cuyas funcionalidades y beneficios se enmarcan en un nuevo paradigma en la administración de base de datos modernas logrando en lo mayor posible satisfacer eficientemente las diversas necesidades y requerimientos concierntes al tratamiento de la data empresarial. Unas de estas nuevas características son las funciones de ranking las cuales sirven para definir diferentes maneras de enumeración secuencial para los resultados, es decir, rankear un result set(A esta altura posiblemente la mayoria de gente ya esté enterada al respecto, sin embargo, como es bien sabido, no todos lo saben,... y para ellos es este post!).

Entre las funcionalidades tenemos por ejemplo, el poder enumerar secuencialmente cada fila de los resultados, tambien enumerar secuencialmente grupos para un set de resultados, es decir, SQL Server 2005 introduce funcionalidad para usar expresiones de ranking para un result set. Esta caracteristica podemos explotarla para ciertos escenarios, por ejemplo, cuando en nuestras aplicaciones .NET se requiera paginar, clasificar y ordenar los resultados en una grilla.

En SQL Server 2000, usábamos TOP para rankear resultados, pero no podiamos especificar el orden del ranking, y si requeriamos dicha funcionalidad se tenia que crear ciertos algoritmos especificos para lograrlo. En SQL Server 2005 usando las funciones de ranking podemos hacer esta tarea mucho más fácil.

Las funciones de ranking son 4: ROW_NUMBER(), RANK (), DENSE_RANK() Y NTILE(integer_expression), cuyas sintaxis pasamos a verlas:

ROW_NUMBER () OVER ([<partition_by_clause>] <order_by_clause>)
RANK () OVER ([<partition_by_clause>] <order_by_clause>)
DENSE_RANK () OVER ([<partition_by_clause>] <order_by_clause>)
NTILE (integer_expression) OVER ([<partition_by_clause>] <order_by_clause>)

Estas expresiones de ranking de basan en ciertos algoritmos que serán aplicados a una columna especifica, y donde en todo momentos se usarán en combinación con las cláusulas PARTITION BY y ORDER BY. Vamos con algunos ejemplos para aclarar el asunto!.

ROW_NUMBER Function

De esta función ya habia escrito algo, y pueden verlo aquí. Por ejemplo:


SELECT ROW_NUMBER() OVER(ORDER BY FirstName) [Nro],
       FirstName,
       LastName,
       Title
FROM   Person.Contact

(resultados parciales)

Opcionalmente podemos usar la cláusula PARTITION BY con cada una de las funciones ranking. Esta cláusula divide (particiona por Title de contacto) el resultado mediante breaks enumerando cada "sub grupo" secuencialmente. por ejemplo:

 
SELECT ROW_NUMBER() OVER(PARTITION BY Title ORDER BY FirstName) [Nro],
       FirstName,
       LastName,
       Title
FROM   Person.Contact
WHERE  [Title] IS NOT NULL

Mostramos sólo las dos últimas particiones para Sr. y Sra). En esta vez estamos particionando por Title y enumerando secuencialmente cada fila para cada grupo. (resultados parciales)

RANK Function

Rankea los datos de acuerdo a lo que se especifique para la cláusula ORDER BY, y lo hace rankeando verdaderamente la enumeración los resultados. Se diferencia de ROW_NUMBER() en lo siguiente. ROW_NUMBER() enumera así: 1,2,3,4,5... cada fila, en cambio RANK() no tendría porque hacerlo necesarimente de la misma manera, pudiendo enumerar así: 1,2,4,4,7,8,8,8,9... Por ejemplo:


SELECT RANK() OVER(ORDER BY FirstName) [Nro],
       FirstName,
       LastName,
       Title
FROM   Person.Contact

(resultados parciales)

DENSE_RANK Function

Es parecido a RANK(), y se diferencia en que no produce saltos en la enumeración de los result set. Es decir, la enumeración sería así: 1,2,2,3,4,5,5,6,7,8,8,9. Enumeración repetida pero secuencial, sin saltar números.

 
SELECT DENSE_RANK() OVER(ORDER BY FirstName) [Nro],
       FirstName,
       LastName,
       Title
FROM   Person.Contact

(resultados parciales)

NTILE Function

Esta función lo que hace es limitar la numeración máxima de los resultados, por ejmplo, si es especifica NTILE(3O00) entonces la numeración será hasta 3000 a partir, obviamente, desde 1. Por ejemplo:


SELECT NTILE(1000) OVER(ORDER BY FirstName) [Nro],
       FirstName,
       LastName,
       Title
FROM   Person.Contact

(resultados parciales)

Para finalizar, paso a mostrar todas las funciones trabajando juntos, usted podrá sacar conclusiones!.

--TODAS LAS FUNCIONES RANKING, TRABAJANDO JUNTOS!!!.
SELECT FirstName,
       LastName,
       Title,
       ROW_NUMBER() OVER(ORDER BY FirstName) [ROW_NUMBER],
       ROW_NUMBER() OVER(PARTITION BY FirstName ORDER BY FirstName) [RN_PARTITION],
       RANK() OVER(ORDER BY FirstName) [RANK],
       DENSE_RANK() OVER(ORDER BY FirstName) [DENSE_RANK],
       NTILE(1000) OVER(ORDER BY FirstName) [NTILE]
FROM   Person.Contact
WHERE  [Title] IS NOT NULL

(resultados parciales)

Hay más combinaciones que se puede hacer entre las funciones de ranking y otras características de SQL Server 2005, como por ejemplo, emplearlos usando CTEs. Este post ha sido bien puntual tratando de dar una visión clara y concisa de estos temas. Comentarios y sugerencias serán todas bienvenidas!.

Percy Reyes.

Publicado por Percy Reyes | 16 comment(s)

Actualización para el Service Pack 1 de SQL Server 2005

Fecha de última publicación: 2/4/2007

Tamaño de la descarga: 24.4 MB

Esta revisión actualiza el entorno de secuencias de comandos de SQL Server Integration Services 2005 (SSIS) para que funcione con una nueva revisión que soluciona un peligro para la seguridad de .Net Framework 2.0. Sin esta revisión, puede que no se ejecute ninguna secuencia de comandos de VB.Net (tarea Secuencia de comandos o componente de secuencia de comandos) de los paquetes SSIS ni que funcione correctamente en tiempo de diseño

Requisitos del sistema
CPU recomendada: 600 MHz
Memoria recomendada: 512 MB
Espacio en disco duro recomendado: 1900 MB

Instrucciones de desinstalación
Esta actualización de software se puede desinstalar a través de la opción Agregar o quitar programas del Panel de control.

Obtención de ayuda y soporte técnico
http://support.microsoft.com

Más información: http://support.microsoft.com/kb/932555

Publicado por Percy Reyes | 7 comment(s)