Actualización de http://electronicaamartillazos.co.nr/ (sección C#) donde muestro cómo usar Linq para crear un programita que desoculta todas las carpetas ocultas (y declaradas como carpetas de sistema) en los directorios raíz de discos duros y memorias extraíbles. Los virus que ocultan carpetas también las declaran como carpetas de sistema, de modo que no se pueden desocultar manualmente.
Este programita sirve como base para hacer programas más complejos que administren los atributos de archivos, carpetas y subcarpetas.
Códigos de ejemplo para aprender distintas tecnologías, o lo que sucede cuando a una cuarentona se la deja sola con una computadora
Acerca de:
Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)
sábado, 8 de octubre de 2011
viernes, 9 de septiembre de 2011
Error en Crystal Reports: "Esta sección de Grupo no se puede imprimir..."
El mensaje completo es:
"Esta Seccion de grupo no se puede imprimir porque su campo de condicion no existe o no es valido. Dar formato a la seccion para elegir otro campo de condicion". Este mensaje de error aparece al querer ir a la pestaña "Vista Previa". Al presionar el botón Aceptar, aparece una página en blanco en lugar del reporte.
Busqué en Internet y no hallé cómo eliminar este error. Tampoco hallé nada útil en la Ayuda de Crystal Reports. Pero, después de probar un poco, dí yo misma con la solución.
Todos los reportes de Crystal Reports van conectados a una Base de Datos. Los grupos del reporte (por ejemplo un encabezado), están vinculadas a un campo específico de la Base de Datos. Esto es para que Crystal Reports sepa en qué orden mostrar los reportes con la data jalada desde la Base de Datos.
Este error se genera al cambiar la conexión a otra Base de Datos, eliminarla, cambiar a otra tabla, y cualquier situación en que el reporte no tenga cómo hallar el campo al que estaba vinculado.
Para solucionar esto, se debe ir al asistente de Base de Datos y configurar o crear la conexión, esto es necesario en caso de haberla eliminado:
Luego, en la pertaña Diseño, le hacemos click derecho al grupo que da problemas y elegimos la opción "Cambiar el Grupo":
Se nos abrirà la ventana que nos permitirá asignar un nuevo campo de condición:
Con esto, ya podemos ir a la Vista Previa de nuestro reporte :D
"Esta Seccion de grupo no se puede imprimir porque su campo de condicion no existe o no es valido. Dar formato a la seccion para elegir otro campo de condicion". Este mensaje de error aparece al querer ir a la pestaña "Vista Previa". Al presionar el botón Aceptar, aparece una página en blanco en lugar del reporte.
Busqué en Internet y no hallé cómo eliminar este error. Tampoco hallé nada útil en la Ayuda de Crystal Reports. Pero, después de probar un poco, dí yo misma con la solución.
Todos los reportes de Crystal Reports van conectados a una Base de Datos. Los grupos del reporte (por ejemplo un encabezado), están vinculadas a un campo específico de la Base de Datos. Esto es para que Crystal Reports sepa en qué orden mostrar los reportes con la data jalada desde la Base de Datos.
Este error se genera al cambiar la conexión a otra Base de Datos, eliminarla, cambiar a otra tabla, y cualquier situación en que el reporte no tenga cómo hallar el campo al que estaba vinculado.
Para solucionar esto, se debe ir al asistente de Base de Datos y configurar o crear la conexión, esto es necesario en caso de haberla eliminado:
Luego, en la pertaña Diseño, le hacemos click derecho al grupo que da problemas y elegimos la opción "Cambiar el Grupo":
Se nos abrirà la ventana que nos permitirá asignar un nuevo campo de condición:
Con esto, ya podemos ir a la Vista Previa de nuestro reporte :D
lunes, 1 de agosto de 2011
Leyendo data numérica desde un archivo de texto con C++
Tengo un archivo de texto que contiene una lista de números con el siguiente formato:
Pero si quiero operar con todos los números en un archivo de texto sin importar cuántos sean, usaré este código:
Ambos códigos han sido probados con el compilador gratuito de Borland.
Cómo usar el compilador, lo explico aquí.
En este link hay información sobre "fscanf" y "rewind". Y aquí hay un tutorial sobre lectura y escritura de archivos con C++.
He llamado al archivo "18.txt" por ninguna razón en especial. Lo que quiero hacer es leer los números en el archivo y realizar algunas operaciones matemáticas con ellos. Como están en formato de texto, primero debo convertirlos a números decimales.
Para ello uso la función "atof", pero hay un problema: mis números usan coma decimal, y la función "atof" considera punto decimal. Debo leer los números, línea por línea, y ponerlos en el formato con el que puede trabajar "atof", así que declaro un aray de caracteres llamado "palabra". Ninguno de los números guardados en "18.txt" ocupa más de cinco caracteres, así que "palabra" es declarada como: char palabra[6];
Luego recorro cada caracter dentro de "palabra" y si encuentro una coma, la reemplazo por un punto.
El array "beta", separa espacio en memoria para 150 números decimales ya que sólo quiero operar con 150 números en total.
El código fuente es el siguiente (el ejecutable compilado está en la misma carpeta que "18.txt"):
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
void main(int argc, char* argv[])
{ FILE *fp;
int i;
double *beta, c, promedio, rms, desviacion;
char palabra[6];
beta = (double *)malloc(sizeof(double)*151);
i=0;
fp = fopen("18.txt", "r");
if (fp==NULL)
cout<<"no existe el archivo \n";
else {
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
void main(int argc, char* argv[])
{ FILE *fp;
int i;
double *beta, c, promedio, rms, desviacion;
char palabra[6];
beta = (double *)malloc(sizeof(double)*151);
i=0;
fp = fopen("18.txt", "r");
if (fp==NULL)
cout<<"no existe el archivo \n";
else {
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta[i] = atof(palabra);
cout<<beta[i];
cout<<"\n";
i++;
}
while (c != EOF && i != 151);
//valores estadísticos:
promedio=0; desviacion=0; rms=0;
//Promedio
for (int j= 0; j<=150; j++)
promedio= promedio+ beta[j];
promedio = promedio/151;
cout<<"Promedio "; cout<<promedio;
cout<<"\n";
//Desviación Estándar
for (int j= 0; j<=150; j++)
desviacion= desviacion + pow((beta[j]-promedio),2);
cout<<beta[i];
cout<<"\n";
i++;
}
while (c != EOF && i != 151);
//valores estadísticos:
promedio=0; desviacion=0; rms=0;
//Promedio
for (int j= 0; j<=150; j++)
promedio= promedio+ beta[j];
promedio = promedio/151;
cout<<"Promedio "; cout<<promedio;
cout<<"\n";
//Desviación Estándar
for (int j= 0; j<=150; j++)
desviacion= desviacion + pow((beta[j]-promedio),2);
desviacion=pow(desviacion,0.5)/pow(151,0.5);
cout<<"la desviacion estandar es: "; cout<<desviacion;
cout<<"\n";
//Valor Cuadrático Medio
for (int j= 0; j<=150; j++)
rms= rms + pow(beta[j],2);
cout<<"la desviacion estandar es: "; cout<<desviacion;
cout<<"\n";
//Valor Cuadrático Medio
for (int j= 0; j<=150; j++)
rms= rms + pow(beta[j],2);
rms=pow(rms,0.5)/pow(151,0.5);
cout<<"El valor RMS: "; cout<<rms;
cout<<"\n";
fclose(fp);
}
system("PAUSE");
}
cout<<"El valor RMS: "; cout<<rms;
cout<<"\n";
fclose(fp);
}
system("PAUSE");
}
Pero si quiero operar con todos los números en un archivo de texto sin importar cuántos sean, usaré este código:
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
void main(int argc, char* argv[])
{ FILE *fp;
double i;
double beta, c, promedio, rms, desviacion;
char palabra[6];
//valores estadísticos:
promedio=0; desviacion=0; rms=0;
i=0;
fp = fopen("18.txt", "r");
if (fp==NULL)
cout<<"no existe el archivo \n";
else {
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta = atof(palabra);
cout<<beta;
cout<<"\n";
i++;
promedio = promedio + beta;
rms = rms + pow(beta,2);
}
while (c != EOF);
promedio = promedio/i;
rms=pow(rms,0.5)/pow(i,0.5);
i=0;
rewind(fp);
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta = atof(palabra);
i++;
desviacion= desviacion + pow((beta-promedio),2);
}
while (c != EOF);
desviacion=pow(desviacion,0.5)/pow(i,0.5);
cout<<"Promedio "; cout<<promedio;
cout<<"\n";
cout<<"la desviacion estandar es: "; cout<<desviacion;
cout<<"\n";
cout<<"El valor RMS: "; cout<<rms;
cout<<"\n";
fclose(fp);
}
system("PAUSE");
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
void main(int argc, char* argv[])
{ FILE *fp;
double i;
double beta, c, promedio, rms, desviacion;
char palabra[6];
//valores estadísticos:
promedio=0; desviacion=0; rms=0;
i=0;
fp = fopen("18.txt", "r");
if (fp==NULL)
cout<<"no existe el archivo \n";
else {
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta = atof(palabra);
cout<<beta;
cout<<"\n";
i++;
promedio = promedio + beta;
rms = rms + pow(beta,2);
}
while (c != EOF);
promedio = promedio/i;
rms=pow(rms,0.5)/pow(i,0.5);
i=0;
rewind(fp);
do
{
c = fscanf(fp, "%s", palabra);
for(int j=0; j<6; j++)
if (palabra[j]== ',')
{ palabra[j]='.'; break; }
beta = atof(palabra);
i++;
desviacion= desviacion + pow((beta-promedio),2);
}
while (c != EOF);
desviacion=pow(desviacion,0.5)/pow(i,0.5);
cout<<"Promedio "; cout<<promedio;
cout<<"\n";
cout<<"la desviacion estandar es: "; cout<<desviacion;
cout<<"\n";
cout<<"El valor RMS: "; cout<<rms;
cout<<"\n";
fclose(fp);
}
system("PAUSE");
}
Ambos códigos han sido probados con el compilador gratuito de Borland.
Cómo usar el compilador, lo explico aquí.
En este link hay información sobre "fscanf" y "rewind". Y aquí hay un tutorial sobre lectura y escritura de archivos con C++.
viernes, 15 de julio de 2011
Calculando la potencia de un número usando recursividad en C#
Primero, el código fuente:
class Potencia
{
static void Main(string[] args)
{
Potencia pot = new Potencia();
double r = pot.potenciaR(2, 1, 3, 0);
Console.WriteLine(r.ToString());
Console.Read();
}
private double potenciaR(double base0, double p, int exponente, int i)
{
return i >= exponente ? p : potenciaR(base0, p * base0, exponente, i + 1);
}
}
Los parámetros de la función "potenciaR" son: base, resultado, exponente, condición de parada.
El parámetro "p" debe ser 1 al inicio porque es el "acumulador" dodne se irá multiplicando la base tantas veces como indique el exponente. La función "potenciaR" deja de llamarse a sí misma cuando el parámetro "i" es igual al valor "exponente". El valor inicial de "i" es cero.
Y a continuación, lo mismo, pero con una expresión lambda recursiva:
Releyendo, noté que podemos suprimir el parámetro "i" y usar el mismo parámetro "exponente" como condición de parada. Para la expresión lambda recursiva queda así:
En todos los casos, el parámetro "p" es siempre 1.
Esta es la web donde aprendí a hacer expresiones lambda recursivas:
http://commanet.blogspot.com/2008/02/recursividad-annima.html
class Potencia
{
static void Main(string[] args)
{
Potencia pot = new Potencia();
double r = pot.potenciaR(2, 1, 3, 0);
Console.WriteLine(r.ToString());
Console.Read();
}
private double potenciaR(double base0, double p, int exponente, int i)
{
return i >= exponente ? p : potenciaR(base0, p * base0, exponente, i + 1);
}
}
Los parámetros de la función "potenciaR" son: base, resultado, exponente, condición de parada.
El parámetro "p" debe ser 1 al inicio porque es el "acumulador" dodne se irá multiplicando la base tantas veces como indique el exponente. La función "potenciaR" deja de llamarse a sí misma cuando el parámetro "i" es igual al valor "exponente". El valor inicial de "i" es cero.
Y a continuación, lo mismo, pero con una expresión lambda recursiva:
class Potencia
{
static void Main(string[] args)
{
Func<double, double, double,double, double> potenciaF = null;
potenciaF = (base0, p, exponente, i) =>
i >= exponente ? p : potenciaF(base0, p * base0, exponente, i + 1);
Console.WriteLine(potenciaF(2, 1, 3, 0).ToString());
Console.Read();
}
}
{
static void Main(string[] args)
{
Func<double, double, double,double, double> potenciaF = null;
potenciaF = (base0, p, exponente, i) =>
i >= exponente ? p : potenciaF(base0, p * base0, exponente, i + 1);
Console.WriteLine(potenciaF(2, 1, 3, 0).ToString());
Console.Read();
}
}
Releyendo, noté que podemos suprimir el parámetro "i" y usar el mismo parámetro "exponente" como condición de parada. Para la expresión lambda recursiva queda así:
class Potencia
{
static void Main(string[] args)
{
Func<double, double, double, double> potenciaF = null;
potenciaF = (base0, p, exponente) =>
exponente <= 0 ? p : potenciaF(base0, p * base0, exponente - 1);
Console.WriteLine(potenciaF(2, 1, 3).ToString());
Console.Read();
}
{
static void Main(string[] args)
{
Func<double, double, double, double> potenciaF = null;
potenciaF = (base0, p, exponente) =>
exponente <= 0 ? p : potenciaF(base0, p * base0, exponente - 1);
Console.WriteLine(potenciaF(2, 1, 3).ToString());
Console.Read();
}
}
Esta es la web donde aprendí a hacer expresiones lambda recursivas:
http://commanet.blogspot.com/2008/02/recursividad-annima.html
viernes, 3 de junio de 2011
VB6 Code Snippet: Mantener la proporción de alto y ancho de una imagen
Tengo una imagen cargada en un control Image en Visual Basic 6. Quiero que esa imagen mantenga su proporción Ancho/Alto cuando el control Image tiene su propiedad Stretch en True. El código para hacerlo es el siguiente (He llamado al control Image imgProporcion):
Dim i As Double, j As Double
Dim proporcion As Double
i = imgProporcion.Width
j = imgProporcion.Height
imgProporcion.Visible = False
imgProporcion.Stretch = False
i = (i / imgProporcion.Width)
j = (j / imgProporcion.Height)
If j > i Then proporcion = j Else proporcion = i
imgProporcion.Stretch = True
imgProporcion.Width = CInt(proporcion * imgProporcion.Width)
imgProporcion.Height = CInt(proporcion * imgProporcion.Height)
imgProporcion.Visible = True
Dim proporcion As Double
i = imgProporcion.Width
j = imgProporcion.Height
imgProporcion.Visible = False
imgProporcion.Stretch = False
i = (i / imgProporcion.Width)
j = (j / imgProporcion.Height)
If j > i Then proporcion = j Else proporcion = i
imgProporcion.Stretch = True
imgProporcion.Width = CInt(proporcion * imgProporcion.Width)
imgProporcion.Height = CInt(proporcion * imgProporcion.Height)
imgProporcion.Visible = True
viernes, 29 de abril de 2011
Haciendo el Test Fizz Buzz con Linq en C#
Leyendo algunos de los muchos blogs de programación flotando por ahí, es muy probable toparse con el Test Fizz Buzz, el que yo ya he usado antes para practicar algunas cosas de programación en C#.
Y por ahí se me ocurrió hacerlo usando Linq. Todo el código es el siguiente:
using System;
using System.Linq;
using System.Collections.Generic;
namespace Operator
{
class Program
{
static void Main(string[] args)
{
int[] fbz = new int[100];
for (int i = 1; i <= 100; i++)
fbz[i - 1] = i;
IEnumerable <string > fizbuz = fbz.Select(
c=> (c % 3 == 0) & (c % 5 == 0) ? "FizzBuzz" :
(c % 3 == 0) ? "Fizz" :
(c % 5 == 0) ? "Buzz" : c.ToString() );
foreach (string c in fizbuz)
Console.WriteLine(c);
Console.Read();
}
}
}
Una cosa interesante del Linq es que tiene algo llamado "Lazy Evaluation" ó "Evaluación perezosa": la ejecución de las instrucciones no se realiza cuando se declara la interfaz IEnumerable "fizbuz", si no cuando se la recorre con el bucle foreach. De esta forma se pueden tener muchas interfaces pertenecientes a System.Collections y recién ejecutar sus códigos cuando se las recorre con un foreach.
Y luego, para cumplir con las condiciones del test, vuelvo a usar el operador ternario "?", el cual me gusta mucho porque marea cuando se lo ve las primeras veces :D :D
Y por ahí se me ocurrió hacerlo usando Linq. Todo el código es el siguiente:
using System;
using System.Linq;
using System.Collections.Generic;
namespace Operator
{
class Program
{
static void Main(string[] args)
{
int[] fbz = new int[100];
for (int i = 1; i <= 100; i++)
fbz[i - 1] = i;
IEnumerable
c=> (c % 3 == 0) & (c % 5 == 0) ? "FizzBuzz" :
(c % 3 == 0) ? "Fizz" :
(c % 5 == 0) ? "Buzz" : c.ToString() );
foreach (string c in fizbuz)
Console.WriteLine(c);
Console.Read();
}
}
}
Una cosa interesante del Linq es que tiene algo llamado "Lazy Evaluation" ó "Evaluación perezosa": la ejecución de las instrucciones no se realiza cuando se declara la interfaz IEnumerable "fizbuz", si no cuando se la recorre con el bucle foreach. De esta forma se pueden tener muchas interfaces pertenecientes a System.Collections y recién ejecutar sus códigos cuando se las recorre con un foreach.
Y luego, para cumplir con las condiciones del test, vuelvo a usar el operador ternario "?", el cual me gusta mucho porque marea cuando se lo ve las primeras veces :D :D
martes, 19 de abril de 2011
C# Code Snippet: Usando el control FontDialog
En una aplicación tipo WindowsApplication tengo un FontDialog, y quiero que cuando el usuario hace click en "Aceptar", los valores de este FontDialog se almacenen en un objeto tipo FontStyle, el que luego se utiliza para crear un objeto tipo Font.
El código es éste:
Aquí hago uso del operador ternario '?' para acortar la expresión donde se asigna el tipo de la fuente. Si no uso este operador, la expresión sería:
if (dlgFont.Font.Bold)
myFontStyle = FontStyle.Bold;
else
if (dlgFont.Font.Italic)
myFontStyle = FontStyle.Italic;
else
if (dlgFont.Font.Underline)
myFontStyle = FontStyle.Underline;
else
if (dlgFont.Font.Strikeout)
myFontStyle = FontStyle.Strikeout;
else
myFontStyle = FontStyle.Regular;
El código es éste:
if (dlgFont.ShowDialog() == DialogResult.OK)
{
{
// asigno el estilo de fuente
myFontStyle =
dlgFont.Font.Bold ? FontStyle.Bold :
dlgFont.Font.Italic ? FontStyle.Italic :
dlgFont.Font.Underline ? FontStyle.Underline :
dlgFont.Font.Strikeout ? FontStyle.Strikeout : FontStyle.Regular;
myFont =
myFontStyle =
dlgFont.Font.Bold ? FontStyle.Bold :
dlgFont.Font.Italic ? FontStyle.Italic :
dlgFont.Font.Underline ? FontStyle.Underline :
dlgFont.Font.Strikeout ? FontStyle.Strikeout : FontStyle.Regular;
myFont =
new Font(dlgFont.Font.Name, dlgFont.Font.Size, myFontStyle);
}
}
Aquí hago uso del operador ternario '?' para acortar la expresión donde se asigna el tipo de la fuente. Si no uso este operador, la expresión sería:
if (dlgFont.Font.Bold)
myFontStyle = FontStyle.Bold;
else
if (dlgFont.Font.Italic)
myFontStyle = FontStyle.Italic;
else
if (dlgFont.Font.Underline)
myFontStyle = FontStyle.Underline;
else
if (dlgFont.Font.Strikeout)
myFontStyle = FontStyle.Strikeout;
else
myFontStyle = FontStyle.Regular;
jueves, 24 de marzo de 2011
VB6: Rutina para Eliminar FIlas Repetidas en un Hierarchical FlexGrid
Esta rutina está pensada para un Hierarchical FlexGrid cuya primera fila (la que tiene el índice 0) contiene los nombres de las columnas, por ello procesa a partir de la fila con índice 1:
Sub eliminar_Repetidos()
Dim estaFila, unaFila As String
Dim i, j, m, n As Integer
estaFila = vbNullString
unaFila = vbNullString
With HierarchicalFlexGrid
m = 1 ' Apunta a la primera Fila
n = .Rows - 1 ' Cantidad de filas del HierarchicalFlexGrid
Do Until m > n
estaFila = vbNullString 'cadena con la Fila Actual
For i = 0 To .Cols - 1
estaFila = estaFila + .TextMatrix(m, i) ' Relleno la cadena con los datos de toda la fila
Next
j = 1
Do Until j > n
unaFila = vbNullString ' Fila a comparar
For i = 0 To .Cols - 1
unaFila = unaFila + .TextMatrix(j, i) ' la relleno con los datos de toda la fila
Next
If estaFila = unaFila And j <> m Then
.RemoveItem (j) ' Si son iguales remuevo unaFila solamente
n = n - 1 ' tamaño actual del HierarchicalFlexgrid, al remover disminuye en uno
End If
j = j + 1
Loop
m = m + 1
Loop
'Chequeo si la última y la penúltima fila son iguales, porque no se eliminan si lo son
For i = 0 To .Cols - 1
estaFila = estaFila + .TextMatrix(.Rows - 1, i)
unaFila = unaFila + .TextMatrix(.Rows - 2, i)
Next
If unaFila = estaFila Then .RemoveItem (.Rows - 2)
End With
End Sub
La rutina hace lo siguiente: cojo la primera fila y, en un bucle, la comparo con todas las demás y voy eliminando las que son iguales a la primera fila. Al terminar paso a la segunda fila y vuelvo a comparar y eliminar si son iguales. Esto se repite hasta llegar al final del Hierarchical FlexGrid.
Este algoritmo es más eficiente que, en dos bucles anidados, marcar las filas repetidas para eliminarlas después.
viernes, 11 de marzo de 2011
Obtener los nombres de las tablas y los nombres de sus esquemas de una BD en SQLServer desde VB6
Un día intentaba conectarme a AdventureWorks sample BD desde una app en Visual Basic 6.
Declaraba un recordset como sigue:
db.Open miConnectionString 'db es un objeto tipo Connection
Set rs = db.OpenSchema(adSchemaTables, Array(Empty, Empty, Empty, "TABLE"))
para poder listar todas sus tablas, usando un bucle.
Mi problema era que al ejecutar un query en SQL:
Dim s as String
Do Until rs.EOF
s="Select * from " & rs!Table_Name
' Hacer muchas muchas cosas con la variable "s"
rs.MoveNext
Loop
Me botaba error, ya que sólo tenía el nombre de la tabla. Para que funcionara, el query dentro de la variable "s" necessitaba también el nombre del esquema (Schema Name) y contruirlo todo de la siguiente forma:
Select * from Schema_Name.Tabla
Luego de mucho rebuscar en Google, hallé esta web
http://www.techrepublic.com/article/much-ado-about-field-properties/1045310
Donde explican lo que hace OpenSchema. Para mi caso, utilizo el SchemaID "AdSchemaTables", el cual incluye un filtro llamado "TABLE_SCHEMA".
Finalmente mi query queda:
Dim s as String
Do Until rs.EOF
s="Select * from " & rs!Table_Schema & "." & rs!Table_Name
' Hacer muchas muchas cosas con la variable "s"
rs.MoveNext
Loop
Update!
Cómo saber si una tabla tiene un nombre de esquema asignado:
Basta añadir este código en el bucle ("miTabla" es una variable tipo String):
miTabla = vbNullString
miTabla = rs!TABLE_SCHEMA
If miTabla <> vbNullString Then
miTabla = rs!TABLE_SCHEMA & "." & rs!TABLE_NAME
Else
miTabla = rs!TABLE_NAME
End If
Declaraba un recordset como sigue:
db.Open miConnectionString 'db es un objeto tipo Connection
Set rs = db.OpenSchema(adSchemaTables, Array(Empty, Empty, Empty, "TABLE"))
para poder listar todas sus tablas, usando un bucle.
Mi problema era que al ejecutar un query en SQL:
Dim s as String
Do Until rs.EOF
s="Select * from " & rs!Table_Name
' Hacer muchas muchas cosas con la variable "s"
rs.MoveNext
Loop
Me botaba error, ya que sólo tenía el nombre de la tabla. Para que funcionara, el query dentro de la variable "s" necessitaba también el nombre del esquema (Schema Name) y contruirlo todo de la siguiente forma:
Select * from Schema_Name.Tabla
Luego de mucho rebuscar en Google, hallé esta web
http://www.techrepublic.com/article/much-ado-about-field-properties/1045310
Donde explican lo que hace OpenSchema. Para mi caso, utilizo el SchemaID "AdSchemaTables", el cual incluye un filtro llamado "TABLE_SCHEMA".
Finalmente mi query queda:
Dim s as String
Do Until rs.EOF
s="Select * from " & rs!Table_Schema & "." & rs!Table_Name
' Hacer muchas muchas cosas con la variable "s"
rs.MoveNext
Loop
Update!
Cómo saber si una tabla tiene un nombre de esquema asignado:
Basta añadir este código en el bucle ("miTabla" es una variable tipo String):
miTabla = vbNullString
miTabla = rs!TABLE_SCHEMA
If miTabla <> vbNullString Then
miTabla = rs!TABLE_SCHEMA & "." & rs!TABLE_NAME
Else
miTabla = rs!TABLE_NAME
End If
jueves, 17 de febrero de 2011
C# y Ms Access: Excepciòn del tipo "Insert Into Syntaxis Error"
Sucedió un día que tenía que insertar unos datitos a una base de datos en Access 2003 usando C#. La base de datos tiene una sola tabla (la llamaré "miTabla") con tres campos: "No", "un_ID" y "Tittle" de tipos numérico, texto y texto, respectivamente.
Mi código era:
Y a pesar de estar todo bien, siempre me tiraba una excepción que decía "Syntaxis Error en Insert Into", o cualquier cosa parecida, en la línea cmd.ExecuteNonQuery().
Después de horas depurando y leyendo foros, encontré por ahí un tip clave:
A las bases de datos en Access no les gustan los campos con nombres como "Date", "login" o "Password".
Entonces el error no estaba en mi Insert Into, si no, posiblemente, en los nombres de mis campos.
Hice una pequeña modificación al código (no a la base de datos) y el problema se resolvió maravillosamente:
Dejo como tarea hallar el cambio que hice :)
Mi código era:
private void AddDato(string No, string ID, string Tittle, ref OleDbConnection cnn)
{
OleDbCommand cmd = new OleDbCommand(
{
OleDbCommand cmd = new OleDbCommand(
"INSERT INTO miTabla (No, un_ID, Tittle) VALUES(@Num, @uID, @nTittle)", cnn);
cmd.Parameters.AddWithValue("@Num", Convert.ToInt32(No));
cmd.Parameters.AddWithValue("@uID", ID);
cmd.Parameters.AddWithValue("@nTittle", Tittle);
cnn.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
cnn.Close();
}
}
cmd.Parameters.AddWithValue("@Num", Convert.ToInt32(No));
cmd.Parameters.AddWithValue("@uID", ID);
cmd.Parameters.AddWithValue("@nTittle", Tittle);
cnn.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
cnn.Close();
}
}
Y a pesar de estar todo bien, siempre me tiraba una excepción que decía "Syntaxis Error en Insert Into", o cualquier cosa parecida, en la línea cmd.ExecuteNonQuery().
Después de horas depurando y leyendo foros, encontré por ahí un tip clave:
A las bases de datos en Access no les gustan los campos con nombres como "Date", "login" o "Password".
Entonces el error no estaba en mi Insert Into, si no, posiblemente, en los nombres de mis campos.
Hice una pequeña modificación al código (no a la base de datos) y el problema se resolvió maravillosamente:
private void AddDato(string No, string ID, string Tittle, ref OleDbConnection cnn)
{
OleDbCommand cmd = new OleDbCommand(
{
OleDbCommand cmd = new OleDbCommand(
"INSERT INTO miTabla ([No], [un_ID], [Tittle]) VALUES(@Num, @uID, @nTittle)", cnn);
cmd.Parameters.AddWithValue("@Num", Convert.ToInt32(No));
cmd.Parameters.AddWithValue("@uID", ID);
cmd.Parameters.AddWithValue("@nTittle", Tittle);
cnn.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
cnn.Close();
}
}
cmd.Parameters.AddWithValue("@Num", Convert.ToInt32(No));
cmd.Parameters.AddWithValue("@uID", ID);
cmd.Parameters.AddWithValue("@nTittle", Tittle);
cnn.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
cnn.Close();
}
}
Dejo como tarea hallar el cambio que hice :)
Suscribirse a:
Entradas (Atom)




