Categoría: cosas técnicas

Posts relacionados con la programación o manejo o configuración de los oredenadores (computadores)

  • VarChar y NVarChar en SQL Server y MySQL el código para VB y C#

    Pues eso… lo prometido es deuda y aquí tienes el código que te prometí del ejemplo correspondiente al post anterior (VarChar y NVarChar en SQL Server) para VB y C#.

    Este código te permite comprobar que usando VARCHAR también puedes agregar caracteres especiales del idioma español: vocales acentuadas, eñes, etc.

    En este ejemplo también uso dos bases de datos (en realidad 3), una de SQL Server y otra de MySQL en un servidor que está en la nube (en un hosting de Internet, concretamente en uno de Domitienda.com que es donde yo tengo mis sitios alojados). La tercera base es una de SLQ Server en mi servidor local (el de SQLEXPRESS).

    El diseño del formulario y el código de VB y C#

    Este es el formulario en modo de diseño (figura 1):

    Figura 1. El formulario en modo de diseño.
    Figura 1. El formulario en modo de diseño.

    Nota:

    En el código tienes la cadena de conexión para las bases de datos que están en «la web» y es posible que dejen de estar disponibles dentro de algún tiempo (no sé si una semana, un mes, un año o un día), así que… si quieres probarlo, usa cuanto antes el código del ZIP que te pondré al final o crea un proyecto a partir de lo que aquí te muestro.

    El proyecto está creado con Visual Studio 2019 Preview 4.3 pero debería cargar también en Visual Studio 2017 y utiliza el .NET Framework 4.7.2.

    El código para Visual Basic .NET

    '------------------------------------------------------------------------------
    ' Prueba de los tipos de SQL VarChar y NVarChar                     (19/Mar/19)
    ' Usando base de SQL Server y MySQL
    '
    '
    ' (c) Guillermo (elGuille) Som, 2019
    '------------------------------------------------------------------------------
    Option Strict On
    Option Infer On
    
    Imports System.Data
    Imports System.Data.SqlClient
    ' Versión de mysql.data.dll: Connector/Net 6.0.3.0
    Imports MySql.Data.MySqlClient
    
    Imports System.Linq
    
    
    Public Class Form1
    
        Private inicializando As Boolean = True
    
        ''' <summary>
        ''' Para las primeras pruebas uso una base local
        ''' </summary>
        Private UsarBaseLocal As Boolean = True
    
        Private ServerName As String = ".\SQLEXPRESS"
        Private DatabaseName As String = "PruebaVarChar"
        Private UsuarioDB As String = "elGuille_info"
        Private PasswordDB As String = "VarChar_19"
    
        Private Tabla As String = "VarCharElGuille"
        ' Campos: Fecha, ConVarChar varchar(50), ConNVarChar nvarchar(50)
        ' en MySQL no hay NVARCHAR y uso TEXT(50)
    
        Private MaxFilas As Integer = 5
    
        ''' <summary>
        ''' La cadena de conexión a la base de datos
        ''' </summary>
        Private Function CadenaConexionSQL() As String
            ConectarSQL()
    
            Dim csb As New SqlConnectionStringBuilder
    
            csb.DataSource = ServerName
            csb.InitialCatalog = DatabaseName
            csb.UserID = UsuarioDB & "SQL"
            csb.Password = PasswordDB
            csb.IntegratedSecurity = False
    
            Return csb.ConnectionString
        End Function
    
        ''' <summary>
        ''' La cadena de conexión a la base de datos
        ''' </summary>
        Private Function CadenaConexionMySQL() As String
            If UsarBaseLocal Then Return "No hay base local de MySQL"
    
            ConectarMySQL()
    
            Dim csb As New MySqlConnectionStringBuilder
    
            csb.Server = ServerName
            csb.Database = DatabaseName
            csb.UserID = UsuarioDB & "My"
            csb.Password = PasswordDB
    
            Return csb.ConnectionString
        End Function
    
    
        ''' <summary>
        ''' Conectar a la base de datos de SQL Server
        ''' </summary>
        Private Sub ConectarSQL()
            If UsarBaseLocal Then
                ServerName = ".\SQLEXPRESS"
            Else
                ServerName = "sql3.servidoreswindows.net"
            End If
        End Sub
    
        ''' <summary>
        ''' Conectar a la base de datos de MySQL.
        ''' Siempre en remoto.
        ''' </summary>
        Private Sub ConectarMySQL()
            ServerName = "mysql1.servidoreswindows.net"
        End Sub
    
    
        ''' <summary>
        ''' Añadir el dato a la base de SQL Server
        ''' </summary>
        Private Function AñadirSQL() As String
            Dim sCon As String = CadenaConexionSQL()
            Dim sel = $"INSERT INTO {Tabla} (Fecha, ConVarChar, ConNVarChar) " &
                      $"VALUES('{DateTime.Now}', '{txtDato.Text}', '{txtDato.Text}')"
    
            Using con As New SqlConnection(sCon)
                Dim cmd As New SqlCommand(sel, con)
    
                Try
                    con.Open()
                    cmd.ExecuteNonQuery()
                    con.Close()
    
                    Return ""
                Catch ex As Exception
                    Return $"ERROR: {ex.Message}"
                End Try
            End Using
        End Function
    
        ''' <summary>
        ''' Añadir el dato a la base de datos de MySQL
        ''' </summary>
        Private Function AñadirMySQL() As String
            If UsarBaseLocal Then Return "No hay base local de MySQL"
    
            Dim sCon = CadenaConexionMySQL()
            ' En MySQL he definido Fecha como varchar(20)
            Dim sel = $"INSERT INTO {Tabla} (Fecha, ConVarChar, ConNVarChar) " &
                      $"VALUES('{DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss")}', '{txtDato.Text}', '{txtDato.Text}')"
    
            Using con As New MySqlConnection(sCon)
                Dim cmd As New MySqlCommand(sel, con)
    
                Try
                    con.Open()
                    cmd.ExecuteNonQuery()
                    con.Close()
    
                    Return ""
                Catch ex As Exception
                    Return $"ERROR: {ex.Message}"
                End Try
            End Using
        End Function
    
        ''' <summary>
        ''' Mostrar los datos de la base de SQLServer
        ''' </summary>
        Private Function MostrarDatosSQL(ByRef dt As DataTable) As String
            Dim orden = If(chkOrden.Checked, "DESC", "ASC")
            Dim sel = $"SELECT TOP ({MaxFilas}) * FROM {Tabla} ORDER BY Fecha {orden}"
    
            Dim sCon = CadenaConexionSQL()
            Dim da As SqlDataAdapter
            dt = New DataTable
    
            Try
                ' Crear un nuevo objeto del tipo DataAdapter
                da = New SqlDataAdapter(sel, sCon)
    
                ' Llenar la tabla con los datos indicados
                da.Fill(dt)
    
                Return $"Recuperadas {dt.Rows.Count} filas."
            Catch ex As Exception
                Return $"ERROR: {ex.Message}"
            End Try
    
        End Function
    
        ''' <summary>
        ''' Mostrar los datos de MySQL
        ''' </summary>
        Private Function MostrarDatosMySQL(ByRef dt As DataTable) As String
            If UsarBaseLocal Then Return "No hay base local de MySQL"
    
            Dim orden = If(chkOrden.Checked, "DESC", "ASC")
            ' MySQL no tiene TOP, usar en su lugar LIMIT
            Dim sel = $"SELECT * FROM {Tabla} ORDER BY Fecha {orden} LIMIT {MaxFilas}"
    
            Dim sCon = CadenaConexionMySQL()
            Dim da As MySqlDataAdapter
            dt = New DataTable
    
            Try
                ' Crear un nuevo objeto del tipo DataAdapter
                da = New MySqlDataAdapter(sel, sCon)
    
                ' Llenar la tabla con los datos indicados
                da.Fill(dt)
    
                Return $"Recuperadas {dt.Rows.Count} filas."
            Catch ex As Exception
                Return $"ERROR: {ex.Message}"
            End Try
    
        End Function
    
        Private Sub btnAñadir_Click(sender As Object,
                                    e As EventArgs) Handles btnAñadir.Click
            Dim msg = ""
    
            msg = AñadirSQL() & vbCrLf
            msg &= AñadirMySQL()
    
            LabelError.Text = msg
    
            btnRefrescar.PerformClick()
        End Sub
    
        Private Sub btnRefrescar_Click(sender As Object,
                                       e As EventArgs) Handles btnRefrescar.Click
            Dim dt As DataTable = Nothing
            Dim msg = ""
            lvDatos.Items.Clear()
    
            Dim i = 5
            Integer.TryParse(txtFilas.Text, i)
            MaxFilas = i
    
            msg = MostrarDatosSQL(dt) & vbCrLf
            asignarDatos("SQL", dt)
    
            Dim lvi = lvDatos.Items.Add("---")
            lvi.SubItems.Add("---")
            lvi.SubItems.Add("---")
            lvi.SubItems.Add("---")
    
            dt = Nothing
            msg &= MostrarDatosMySQL(dt)
            asignarDatos("MySQL", dt)
    
            LabelError.Text = msg
        End Sub
    
        Private Sub asignarDatos(base As String, dt As DataTable)
            If dt Is Nothing Then Return
    
            For Each r As DataRow In dt.Rows
                Dim lvi = lvDatos.Items.Add(base)
                lvi.SubItems.Add(r("Fecha").ToString)
                lvi.SubItems.Add(r("ConVarChar").ToString)
                lvi.SubItems.Add(r("ConNVarChar").ToString)
            Next
    
        End Sub
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            inicializando = False
        End Sub
    
        Private Sub ChkUsarBaseLocal_CheckedChanged(sender As Object, e As EventArgs) Handles chkUsarBaseLocal.CheckedChanged
            If inicializando Then Return
    
            UsarBaseLocal = chkUsarBaseLocal.Checked
        End Sub
    
    End Class
    

    El código para C#

    //-----------------------------------------------------------------------------
    // Prueba de los tipos de SQL VarChar y NVarChar                    (21/Mar/19)
    // Usando base de SQL Server y MySQL
    //
    //
    // (c) Guillermo (elGuille) Som, 2019
    //-----------------------------------------------------------------------------
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    using System.Data.SqlClient;
    // Versión de mysql.data.dll: Connector/Net 6.0.3.0
    using MySql.Data.MySqlClient;
    
    namespace VarChar_y_NVarChar_cs
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private bool inicializando = true;
    
            /// <summary>
            /// Para las primeras pruebas uso una base local
            /// </summary>
            private bool UsarBaseLocal = true;
    
            private string ServerName = @".\SQLEXPRESS";
            private string DatabaseName = "PruebaVarChar";
            private string UsuarioDB = "elGuille_info";
            private string PasswordDB = "VarChar_19";
    
            private string Tabla = "VarCharElGuille";
            // Campos: Fecha, ConVarChar varchar(50), ConNVarChar nvarchar(50)
            // en MySQL no hay NVARCHAR y uso TEXT(50)
    
            private int MaxFilas = 5;
    
            /// <summary>
            /// La cadena de conexión a la base de datos
            /// </summary>
            private string CadenaConexionSQL()
            {
                ConectarSQL();
    
                var csb = new SqlConnectionStringBuilder();
    
                csb.DataSource = ServerName;
                csb.InitialCatalog = DatabaseName;
                csb.UserID = UsuarioDB + "SQL";
                csb.Password = PasswordDB;
                csb.IntegratedSecurity = false;
    
                return csb.ConnectionString;
            }
    
            /// <summary>
            /// La cadena de conexión a la base de datos
            /// </summary>
            private string CadenaConexionMySQL()
            {
                if (UsarBaseLocal)
                    return "No hay base local de MySQL";
    
                ConectarMySQL();
    
                var csb = new MySqlConnectionStringBuilder();
    
                csb.Server = ServerName;
                csb.Database = DatabaseName;
                csb.UserID = UsuarioDB + "My";
                csb.Password = PasswordDB;
    
                return csb.ConnectionString;
            }
    
    
            /// <summary>
            /// Conectar a la base de datos de SQL Server
            /// </summary>
            private void ConectarSQL()
            {
                if (UsarBaseLocal)
                    ServerName = @".\SQLEXPRESS";
                else
                    ServerName = "sql3.servidoreswindows.net";
            }
    
            /// <summary>
            /// Conectar a la base de datos de MySQL.
            /// Siempre en remoto.
            /// </summary>
            private void ConectarMySQL()
            {
                ServerName = "mysql1.servidoreswindows.net";
            }
    
    
            /// <summary>
            /// Añadir el dato a la base de SQL Server
            /// </summary>
            private string AñadirSQL()
            {
                string sCon = CadenaConexionSQL();
                var sel = $"INSERT INTO {Tabla} (Fecha, ConVarChar, ConNVarChar) " + 
                          $"VALUES('{DateTime.Now}', '{txtDato.Text}', '{txtDato.Text}')";
    
                using (var con = new SqlConnection(sCon))
                {
                    var cmd = new SqlCommand(sel, con);
    
                    try
                    {
                        con.Open();
                        cmd.ExecuteNonQuery();
                        con.Close();
    
                        return "";
                    }
                    catch (Exception ex)
                    {
                        return $"ERROR: {ex.Message}";
                    }
                }
            }
    
            /// <summary>
            /// Añadir el dato a la base de datos de MySQL
            /// </summary>
            private string AñadirMySQL()
            {
                if (UsarBaseLocal)
                    return "No hay base local de MySQL";
    
                var sCon = CadenaConexionMySQL();
                // En MySQL he definido Fecha como varchar(20)
                var sel = $"INSERT INTO {Tabla} (Fecha, ConVarChar, ConNVarChar) " + 
                          $"VALUES('{DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss")}', '{txtDato.Text}', '{txtDato.Text}')";
    
                using (var con = new MySqlConnection(sCon))
                {
                    var cmd = new MySqlCommand(sel, con);
    
                    try
                    {
                        con.Open();
                        cmd.ExecuteNonQuery();
                        con.Close();
    
                        return "";
                    }
                    catch (Exception ex)
                    {
                        return $"ERROR: {ex.Message}";
                    }
                }
            }
    
            /// <summary>
            /// Mostrar los datos de la base de SQLServer
            /// </summary>
            private string MostrarDatosSQL(ref DataTable dt)
            {
                var orden = chkOrden.Checked ? "DESC" : "ASC";
                var sel = $"SELECT TOP ({MaxFilas}) * FROM {Tabla} ORDER BY Fecha {orden}";
    
                var sCon = CadenaConexionSQL();
                SqlDataAdapter da;
                dt = new DataTable();
    
                try
                {
                    // Crear un nuevo objeto del tipo DataAdapter
                    da = new SqlDataAdapter(sel, sCon);
    
                    // Llenar la tabla con los datos indicados
                    da.Fill(dt);
    
                    return $"Recuperadas {dt.Rows.Count} filas.";
                }
                catch (Exception ex)
                {
                    return $"ERROR: {ex.Message}";
                }
            }
    
            /// <summary>
            /// Mostrar los datos de MySQL
            /// </summary>
            private string MostrarDatosMySQL(ref DataTable dt)
            {
                if (UsarBaseLocal)
                    return "No hay base local de MySQL";
    
                var orden = chkOrden.Checked ? "DESC" : "ASC";
                // MySQL no tiene TOP, usar en su lugar LIMIT
                var sel = $"SELECT * FROM {Tabla} ORDER BY Fecha {orden} LIMIT {MaxFilas}";
    
                var sCon = CadenaConexionMySQL();
                MySqlDataAdapter da;
                dt = new DataTable();
    
                try
                {
                    // Crear un nuevo objeto del tipo DataAdapter
                    da = new MySqlDataAdapter(sel, sCon);
    
                    // Llenar la tabla con los datos indicados
                    da.Fill(dt);
    
                    return $"Recuperadas {dt.Rows.Count} filas.";
                }
                catch (Exception ex)
                {
                    return $"ERROR: {ex.Message}";
                }
            }
    
            private void BtnAñadir_Click(object sender, EventArgs e)
            {
                var msg = "";
    
                msg = AñadirSQL() + "\n";
                msg += AñadirMySQL();
    
                LabelError.Text = msg;
    
                btnRefrescar.PerformClick();
            }
    
            private void BtnRefrescar_Click(object sender, EventArgs e)
            {
                DataTable dt = null;
                var msg = "";
                lvDatos.Items.Clear();
    
                var i = 5;
                int.TryParse(txtFilas.Text, out i);
                MaxFilas = i;
    
                msg = MostrarDatosSQL(ref dt) + "\n";
                asignarDatos("SQL", dt);
    
                var lvi = lvDatos.Items.Add("---");
                lvi.SubItems.Add("---");
                lvi.SubItems.Add("---");
                lvi.SubItems.Add("---");
    
                dt = null;
                msg += MostrarDatosMySQL(ref dt);
                asignarDatos("MySQL", dt);
    
                LabelError.Text = msg;
            }
    
            private void asignarDatos(string @base, DataTable dt)
            {
                if (dt == null) return;
    
                foreach (DataRow r in dt.Rows)
                {
                    var lvi = lvDatos.Items.Add(@base);
                    lvi.SubItems.Add(r["Fecha"].ToString());
                    lvi.SubItems.Add(r["ConVarChar"].ToString());
                    lvi.SubItems.Add(r["ConNVarChar"].ToString());
                }
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                inicializando = false;
            }
    
            private void ChkUsarBaseLocal_CheckedChanged(object sender, EventArgs e)
            {
                if (inicializando) return;
    
                UsarBaseLocal = chkUsarBaseLocal.Checked;
            }
        }
    }
    

    Y esto es todo… espero que te sea de utilidad.

    Nos vemos.
    Guillermo

    El código completo del ejemplo
    (solución para Visual Studio usando .NET 4.7.2)

    El ZIP con el código completo (una solución de Visual Studio 2019 Preview con los proyectos de Visual Basic y C# además de la DLL de MySQL con la referencia a la copia dentro del directorio de la solución.

    El zip: VarChar_y_NVarChar_20190321.zip (147 KB)

    MD5 Checksum: 888346C11622183F6A39FE5FBA4339D3

    Nota:

    Aquí tienes el enlace para la descarga del ZIP que me descargué con el conector de MySQL para .NET versión 6.0.3 (mysql-connector-net-6.0.3-noinstall.zip) el tamaño es 1.64MB y el MD5 Checksum es: 57BB7F42645665D5A616A3484041F0C0.

  • VarChar y NVarChar en SQL Server

    Actualizado el 21/Mar/2019 con los pasos para resolver el fallo que tenía de acceso a las bases de datos remotas y también con el enlace al código para VB y C#.

    Pues eso… el otro día estaba creando una base de datos de MySQL y me di cuenta que MySQL no tiene el tipo NVARCHAR o al menos a mí no me daba la opción de crear un campo con ese tipo, al menos desde el panel de control del hosting que utilizo (Domitienda.com), así que… utilicé VARCHAR, el problema que me temía que iba a tener era no poder usar las vocales acentuadas (con tilde), la eñe, etc. Pero resultó que sí… que lo aceptaba sin problemas.

    Así que, me puse a buscar en Internet a ver cuál era la diferencia entre VARCHAR y NVARCHAR, ya que yo siempre usaba NVARCHAR en mis bases de SQL Server (que es el tipo de base que uso, salvo excepciones muy, muy contadas) porque era el tipo que me permitía usar los caracteres especiales del idioma español (o al menos así lo entendí yo, que puede ser que lo entendiese mal… ).

    Pero resulta que si utilizo VARCHAR puedo indicar esos caracteres especiales sin mayor problema.

    Por supuesto la información que encontré hablando de esa diferencia entre esos dos tipos de datos era… bueno… no aclaratoria del todo… pero en realidad me daba igual lo que me quisieran decir, ya que yo he comprobado por mí mismo que se puede guardar algo así: Raúl Rodríguez López es de Valdepeñas en un campo del tipo VARCHAR.

    Un ejemplo para acceder a SQL Server y MySQL

    Aquí tienes una captura de un ejemplo que he hecho para mostrar que sí funciona eso de guardar los caracteres especiales, al menos los usados en español.

    El código lo publicaré otro día, ya que es tarde y además no me funciona el código para acceder a las bases de datos remotas (en el hosting de Domitienda), seguramente habré configurado algo mal, ya que a otras que tengo en el mismo hosting si que puedo acceder…

    Nota del 21 de Marzo:

    Según parece resulta que en el «plesk» del hosting no permite usar el mismo nombre de usuario para varias bases de datos o bien la longitud de la contraseña debe ser menor de la que usé… en cualquier caso lo he solucionado haciendo lo siguiente:

    He creado dos usuarios diferentes, el de la base de datos de SQL Server se llama elGuille_infoSQL y el de MySQL se llama elGuille_infoMy.

    He usado una clave más corta.

    Y ahora todo funciona bien… o casi… ya que añadí un campo DATETIME a la base de MySQL y da error al convertir el contenido de la base de datos a un tipo DateTime de .NET, así que… lo he creado como VARCHAR(20).

    Otra cosa con la que me he encontrado con la consulta de MySQL es que no acepta TOP para indicar el número de filas a devolver, en su lugar he usado LIMIT y ya va bien.

    En la captura de la Figura 2 puedes ver la aplicación totalmente operativa y accediendo a las bases de datos remotas.

    Si te fijas en los valores mostrados al final con todo a cero, eso era lo que había añadido usando el tipo de datos DATETIME en MySQL, después al añadirlo como VARCHAR ya se muestra bien.

    El código de VB y C# lo puedes ver en la entrada publicada el 21 de marzo: VarChar y NVarChar en SQL Server y MySQL el código para VB y C#.

    Figura 2. La aplicación operativa con acceso remoto después de los cambios hechos en el hosting.
    Figura 2. La aplicación operativa con acceso remoto después de los cambios hechos en el hosting.

    Figura 1. Formulario de prueba
    Figura 1. El formulario de prueba

    Los datos mostrados en la figura 1 son de una base de datos de SQL Server usada localmente, el mensaje de error que se muestra es el devuelto por el servidor de MySQL.

    Lo importante es que puedes comprobar que tanto el campo VARCHAR como NVARCHAR muestran las vocales con tilde y la eñe.

    Seguramente si uso caracteres de otros idiomas como el CHINO o RUSO no se guardarían bien en el VARCHAR… no lo sé porque no lo he probado… 😉

    Pues esto es todo por hoy… en los enlaces puedes ver más información sobre esos tipos de datos (en la documentación de SQL Server) y lo que cuentan en algunos sitios sobre la diferencia entre ellos.

    Este enlace es sobre VARCHAR en la documentación de MySQL.

    A ver si el jueves próximo (día 21, luna llena, por más señas) te pongo el código de ejemplo de la aplicación que guarda esos caracteres en los dos tipos de datos y como de costumbre tanto para Visual Basic como para C#.

    Nos vemos.
    Guillermo

    Nota:
    Según el panel de control la versión de MySQL es:

    mysql1.servidoreswindows.net
    Versión del servidor: 5.1.73-log

  • Un regalito a una suscripción a Visual Studio Enterprise (por 12 meses)

    Pues eso… que te acabo de contar que la licencia de Visual Studio 2017 Professional que parecía que me habían dado hace unos meses ya había expirado (y parecía que era definitiva y no de prueba) y acabo de abrir el correo y me encuentro que me han dado una suscripción a Visual Studio Enterprise (válida por un año) tal como puedes ver en la captura de la figura 1.

    Un regalito para un ex-MVP (ahora rMVP)
    Figura 1. Un regalito para un ex-MVP (ahora rMVP)

    Esta suscripción (para 12 meses) contiene el Visual Studio y muchas más cosas (Windows, Office, etc.), como las antiguas suscripciones a MSDN que nos daban a los MVP reconocidos como developers… pero esta vez la dan por 12 meses a algunos ex-MVP ahora llamados MVP Reconnect (rMVP) y puede que la renueven… a ver qué pasa dentro de un año.

    ¡Muchas gracias!

    Nos vemos.
    Guillermo