Buscar registros que coincidan con múltiples parámetros en una base de datos desde un UserForm

25/04/2007 - 23:51 por Insumos | Informe spam
Hola Gente del Foro:

Espero que todos esten muy bien. Les cuento cual es mi pregunta de hoy.
Resulta que tengo una hoja llamada "Base" con una base de datos con 7
campos, siendo los campos:

Número Empresa Sucursal Fecha Beneficiario
Concepto Importe

Ahora, en un UserForm he implementado un buscador, para que de acuerdo a los
parámetros ingresados construya, al clickear un CommnadButton, en una hoja
llamada "Reporte" un reporte con los registros que coinciden con los
parámetros ingresados . Los parámetros para buscar en la base se ingresan
así:
Primer Número a buscar (desde) en TextBox2
Último Número a buscar (hasta) en TextBox3
Empresa en ComboBox2
Sucursal en ComboBox3
Primera Fecha a buscar (desde) en TextBox6
Última Fecha a buscar (hasta) en TextBox5
Beneficiario en ComboBox4
Concepto en ComboBox5
Importe en TextBox6

Lo que quiero es que el código busque los registros que coinciden con todos
los parámetros, pero que si en uno de los parámetros no se completó nada o
bien ignore ese parámetro para la búsqueda o bien interprete que ese
parámetro tiene valor "cualquiera". No se me ocurre como hacer esto!
Estuve experimentando con códigos del tipo:

With Worksheets("Base")
For Each celda In .Range("A2:A" & .[A65536].End(xlUp).Row)
If celda.Offset(0, 1) = ComboBox2 Then
If celda.Offset(0, 2) = ComboBox3 Then
celda.EntireRow.Copy
Worksheets("Reporte").[A65536].End(xlUp).Offset(1) _
.PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, SkipBlanks:=False, _
Transpose:=False
End If
End If
Next

Con un código de este estilo puedo lograr que traiga los registros que
coinciden con los parámetros, pero con los siguientes problemas: a) Cuando
no se completa nada en un parámetro lo toma como que debe traer los
registros que estan "vacios" en ese campo, b) Entro en una casi infinita
sucesión de código del tipo IF y tal vez exista una manera de hacer esto sin
eroscar IF tras IF.
Bueno, espero me haya explicado bien. Desde ya muchas gracias por todo!!
Saludos

Mariano

CONTADURIA

Preguntas similare

Leer las respuestas

#11 Ivan
05/05/2007 - 00:31 | Informe spam
hola Mariano, gracias por la informacion, aunque me temo que, como tu dices
habra que esperar a la ayuda/opinion de terceros para salir de dudas con
Empty

en cuanto a tus preguntas, lo 1º un comentario por si lo desconoces: prueba
a situar el cursor sobre cualquiera de esos terminos (o sobre cualquier otro
sobre el que tengas dudas) y pulsa 'F1', te aparecera la ayuda referida al
mismo (si es que existe o no esta oculta). En un principio la ayuda puede
resultar un poco confusa, pero poco a poco le vas cogiendo el tranquillo, y,
realmente 'ayuda', aunque, como dice HM, (mas o menos), cada uno avanza al
ritmo que quiere/puede/necesita o le apetece .

de todas formas, como hace muy poco que he pasado por ahi (de hecho sigo
pasando aunque sea con otros temas/terminos etc) se que se agrdece cualquier
ayuda añadida. Te comento mi 'percepcion' de los terminos que expones, pero
no te fies demasiado de lo que te diga y no te olvides de contrastarla,
tanto con F1 como con lo que puedas buscar/encontrar por el foro o donde sea
(no seria extraño que te diga alguna burrada)

1._> Que significa Option Explicit?

es una instruccion que te obliga a declarar todas las variables
explictamente (Pej: Dim variable, Public Variable as String, Private
Variable, . etc), donde la primera parte (Dim, Public, etc ) hace referencia
al 'alcance' ( osea +o- desde donde se puede trabajar con ella ) de la
variable, lo siguiente seria el nombre de la variable, y por ultimo se
declararia el 'Tipo' de los datos que va a representar la variable (String,
Long, Variant). Aunque el tipo no es obligatorio declararlo, si suele ser
recomendable, pues si no lo haces se considerara de tipo Variant, que si no
me equivoco es la que mas memoria ocupa/necesita

volviendo a option Explicit, tambien es recomendable declaralo, pues asi el
propio editor te avisa de posibles errores, omisiones, etc, que de otra
forma podrian pasar inadvertidos durante el diseño pero darte problemas
durante la ejecucion. Para que esta declaracion te aparezca por omision
siempre cuando abras un modulo (suelen recomendarlo los experto, sobre todo
alos inexpertos como nosotros) puedes ir al menu herramientas -> opciones ->
y actvar la casilla 'Requerir declaracion de variables' . Ahora, cada vez
que abras o insertes un modulo, veras que comienza por 'Option Explicit', y
aunque pued resultar un tanto mas molesto, pues te avisara con mas
frecuencia de posibles omisiones, asi te aseguras de no dejar flecos sueltos
por ese lado.

2.-> Hay algunas comandos que nunca habia visto

2.1.-Ubound, -> te devuelve el indice superior de una matriz, que no tiene
por que ser exactamente (creo) el nº de elementos, pues esto depende pej. de
otro 'Option' Option Base que, si no me equivoco puede ser 0 (al menos hasta
VB6 creo que es el predeterminado) o 1. Esto quiere decir que muchas veces
hay que contar elementos desde 0 hasta uno menos que el nº de elementos (ya
lo habras visto seguramente con la propiedad .listindex de algunos controles
< aunque creo que a esta `propiedad no le afecta Option Base>) sin embargo
si establecemos option base en 1 se contaria desde 1 hasta el ultimo.
Bueno, creo que mejor lo veras en F!, en cualquier caso con Ubound te
aseguras de que haces referencia a ese limite maximo (por ej. para un bucle,
como creo que era el caso)

2.2.-CLng -> es una ¿funcion? convertidora de tipos. En este caso
convierte un dato (valido) al tipo de datos Long. Es algo parecido al Val
que usas para reconvertir en nº el contenido de un textbox, etc. (o a VALOR
en formulas de hoja) pero devolviendo un nº de ese tipo especifico. De todas
formas esto lo veras mucho mejor en la ayuda. Mira tambien Tipos de datos,
yConversion de tipos (o similar)


2.3.-Preserve -> no estoy muy ducho en el tema, pero en definitiva lo que
(creo) que hace es conservar los valores que tiene una matriz cuando la
redimensionamos, o sea, le añadimos elementos. Si no se usa, la matriz toma
los nuevos datos pero no conserva los anteriores ( no me hagas mucho caso,
las matrices son otra de esas espinas con las que estoy peleando). En
cualquier caso, ya sabes , F1

3.-> Para que sirven las variables tipo Boolean? Puede ser que tomen valor
True o
Mostrar la cita
4.-> Ya prové lo del Array.. Un Array se puede usar también para
otras cosas más complejas, verdad?

como te comentaba mis lagunas con las matrices son considerables, pero una
cosa que creo que podria definir un Array/matriz es que es una especie de
'contenedor' de 'casi' cualquier cosa, en el que puedes almacenar o ir
almacenado elementos para poder disponer de ellos en donde te venga bien,
por ejemplo mediante un contador que recorra sus elementos (como si fuera
una 'coleccion', pero...) y realizar operaciones o lo que quieras (como
siempre creo que casi) con ellos.

bueno, no se si te he ayudado o todo lo contrario, pero en cualquier caso
esto yo tambien lo he aprendido 'aqui', y es mas mi 'percepcion' que mi
conocimiento. Por eso no dejes de recurrir a F1, lo agradeceras.

un saludo y hasta pronto
Ivan

PD: en cuanto al ej. que te mande, ahora mismo creo que tengo algo que te
interesara, pues se acerca bastante a tu consulta original en estado puro,
en cuanto quite la basura, si te interesa te lo mando (o si, como creo que,
se reduce bastante te pongo aqui los codigos)
#12 Ivan
05/05/2007 - 01:02 | Informe spam
hola de nuevo Mariano, creo que se me habia escapado esto:

Mostrar la cita
aunque te remito nuevamente a F1 y al buscador del foro. te digo mi
'opinion'

las variables que hay entre los parentesis de los proc. sub o function en
realidad son 'argumentos' que tu le pasas a dicho procedimiento, bien para
que operen con ellos, bien para condicionar una accion dentro de dicho
procedimiento, etc), es como en las funciones de hoja de calculo, pej.
BuscarV (dato buscado, rango en el que buscar, etc).

En cuanto a ByRef y a ByVal la diferencia (considerable) dicho en plan basto
es que lo que le pases con ByRef saldra modificado del procedimiento si lo
has usado/modificado dentro de el y con ByVal lo usa para los fines que sean
pero sale del procedimiento tal y como entro, o sea, en el caso de que lo
que le estes pasando como argumento sea una variable, en el primer caso
saldra con los posibles cambios que le hayas realizado, y en el 2º saldra
tal cual entro.

bueno esto es un poco a nivel practico y muy basico, la realidad tiene que
ver con puntos de almacenamiento/reserva en la memoria, pero creo que de
momento te liaria mas que otra cosa.

si quieres prueba este sencillo ej. que al menos te empezara a dar una idea
(pega todo y ejecuta solo testByRef_ByVal).


Sub testByRef_ByVal()
Dim n1 As Long, n2 As Long
n1 = 15
n2 = 15
Call testByRef(n1)
Call testByval(n2)
MsgBox _
"Valor de n1 antes de entrar a testByref = 15 " & vbCr & _
"Valor de n2 antes de entrar a testByVal = 15 " & vbCr & _
vbCr & "Valor de n1 al salir de testByref = " & n1 & vbCr & _
"Valor de n2 al salir de testByVal = " & n2
End Sub
Sub testByRef(ByRef n_1 As Long)
n_1 = n_1 * 10
End Sub
Sub testByval(ByVal n_2 As Long)
n_2 = n_2 * 10
End Sub

y en cuanto a Optional, simplemente dice si el argumento es obligatorio u
opcional. Pero mejor que le eches un vistazo 1º en la ayuda que seguir
liandote yo

Una saludo y hasta pronto
Ivan
#13 Insumos
08/05/2007 - 02:25 | Informe spam
Hola Ivan:

Te agradezco nuevamente tu amable respuesta. Así de a poco voy aprendiendo
un poco más! Con respecto a la ayuda del Excel, es verdad lo que decís de
que es práctica para consultarla. No se me había ocurrido verla con esos
comandos, aunque ya la había utilizado en otras ocasiones. Lo que sucede es
que a veces no es muy clara, pero buscar información en el foro muchas veces
despeja mejor las dudas!
En fin, muchisimias gracias por todo, y cualquier cosa nos volveremos a
comunicar por este medio.
Saludos.

Mariano

"Ivan" escribió en el mensaje
news:
Mostrar la cita
basto
Mostrar la cita
sean
Mostrar la cita
idea
Mostrar la cita
#14 Ivan
18/05/2007 - 01:25 | Informe spam
hola Mariano,

disculpame por pesado, pero como he seguido utilizando tu ej. para ir
aprendiendo sobre los filtros avanzados, y, gracias de nuevo a una respuesta
de Hector Miguel, creo que he conseguido lo que para mi es un 'paso de
gigante'.

y, aunque posiblemente ya tengas cerrado el tema, creo que te interesara
echar un vistazo a estos codigos, sencillos dentro de lo que cabe, y que
filtran segun todos los criterios que expones (esta vez los reales de esta
primera consulta) en un solo paso y en un santiamen, usando los mencionados
filtros y una formula como criterio.

te pongo los codigos y te los comento entre medias un poco. Aunque parecen
muy largos, no lo son tanto:, y presta atencion a los comentarios que van
entre lineas, que aunque no describen el funcionamiento, si a lo que hacen
referencia.

OJO: los campos son los mismos que en tu 1ª consulta, pero los nombres de
los controles no son exactos, adaptalos, asi como sus respectivos campos. De
todas formas te pongo la relacion que llevan en el ej:( Los titulos van en
la fila 1 y los datos empiezan en la 2:)

Nùmero -> TextBox1 y TextBox2 -> Columna A // Empresa -> ComboBox1 -> col B
// Sucursal -> combo2 -> col C // Fecha -> TextBox3 y TextBox4 -> col D //
Beneficiario -> combo3 -> col E // Concepto -> Combo 4 -> col F //
Importe -> TextBox5 -> col G

'**Copia desde aqui y pegalo en el modulo del formulario**
'
'devueve una cadena con los datos de los Controles
'-que contienen datos validos y el/los operadores
' que se usaran como criterio en el filtrado. Le damos
' el formato de la funcion de hoja de calculo 'Y', para pasarsela
'-como criterio al procedimiento que filtrara los datos
'
Function CriteriosCtls() As String
Dim nCt As Long, Valor As Long, fecha As Long, _
strCriterio As String, strControles As String, _
operador

' cadena con el nombre de todos los controles que se van
' a evaluar separados por 'un' espacio y, a ser posible
' en el orden que estan sus correspondientes campos
'
strControles = "TextBox1 TextBox2 ComboBox1 " & _
"ComboBox2 TextBox3 TextBox4 " & _
"ComboBox3 ComboBox4 TextBox5"

' matriz creada con la funcion Array cuyos elementos
' se forman con la ref. de la primera celda de 'datos'
' del campo en que busca los datos el control que esta
' en la misma posicion de 'strControles. (pej. A2).
' a esta ref. se le une el operador que vamos a usar
' como criterio de comparacion (pej: [>=] para el 1er
' textbox tanto de nro. como de fechas, [<=] para el 2º
' tambien para nros. y fechas, [=] para los combos y
' el ultimo textbox. OJO: fijate que para los campos
' Nro. y fecha, el campo es el mismo para los dos
' textbox respectivos: 'a2' para los nros. 'd2' fechas
'
operador = Array("a2>=", "a2<=", "b2=", "c2=", _
"d2>=", "d2<=", "e2=", "f2=", "g2=")

' strCriterio se ira rellenando con los datos de los controles
' que contengan datos validos concatenados a su respectivo
' campo y operador de comparacion.
'
strCriterio = "": Valor = 0: fecha = 0
For nCt = LBound(Split(strControles)) To _
UBound(Split(strControles))
With Me.Controls(Split(strControles)(nCt))
If Trim(.Text) <> "" Then

' este select Case discrimina el dato y su tipo para
' convertirlo al adecuado y asignarle el operador adecuado
' concatenandolo con los que vayan cumpliendo los
' requisitos
'
Select Case nCt
Case Is = 0, Is = 1, Is = 8
If IsNumeric(.Text) Then
If strCriterio = "" Then
Valor = CLng(.Text)
strCriterio = operador(nCt) & Valor
Else
If nCt = 1 And CLng(.Text) < Valor Then _
Valor = Valor Else Valor = CLng(.Text)
strCriterio = strCriterio & "," & _
operador(nCt) & Valor
End If
End If
Case Is = 4, Is = 5
If IsDate(.Text) Then
fecha = CLng(CDate(.Text))
If strCriterio = "" Then
strCriterio = operador(nCt) & fecha
Else
If nCt = 5 And CLng(CDate(.Text)) > fecha Then _
fecha = CLng(CDate(.Text))
strCriterio = strCriterio & "," & _
operador(nCt) & fecha
End If
End If
Case Else
If strCriterio = "" Then
strCriterio = operador(nCt) & _
"""" & Trim(.Text) & """"
Else
strCriterio = strCriterio & "," & _
operador(nCt) & """" & Trim(.Text) & """"
End If
End Select
End If
End With
Next

' finalmente, si existen datos (validos) en algun control
' completa la cadena con el operador 'and' y los
' parentesis de apertura y cierre
'
If strCriterio <> "" Then _
CriteriosCtls = "=and(" & strCriterio & ")"
End Function
'
'-
'-filtra la lista con los siete campos en base a la
'formula pasada como criterio
'
Sub CoincidenciasDatos(ByVal criterio As String)
Dim ultF As Long
Application.ScreenUpdating = False
With ThisWorkbook.Worksheets(B_Dat)
On Error Resume Next
.ShowAllData
On Error GoTo 0
If .AutoFilterMode Then .AutoFilterMode = False
ultF = .[a65536].End(xlUp).Row
.[i:s].ClearContents
.[i2].Formula = criterio
.Range("a1:g" & ultF).AdvancedFilter _
Action:=xlFilterCopy, _
criteriarange:=.[i1:i2], _
copytorange:=.[k1:q1], _
unique:=False
.[i2].Clear
Application.CutCopyMode = False
'
' aqui lo que se hace es llenar un listbox con las coincidencias
' pero el mismo rango seria valido para traspasarlo a una hoja
' OJO: si decides probar el ListBox ponle 7 columnas
'
If .[k2] <> "" Then
ListBox2.List = .Range("k2:q" & _
.[k65536].End(xlUp).Row).Value
Else
ListBox2.Clear
End If
End With
Application.ScreenUpdating = True
End Sub
'
'--
' codigo para un boton, o para poner en el evento exit (pej) de cada
' control (aunque para no hacer saltar el codigo innecesariamente,
' si te decides por esto, convendria que usaras una variable publica
' o la propiedad Tag para ver si el contenido del control ha cambiado,
' asignandole el valor del control al entrar en él (en el evento Enter
pej.
' poner EseControl.Tag = EseControl.Text) y verificarlo antes de llamar
' al filtro (en Exit pej. algo asi
' If EseControl.Text = EseControl.Tag then exit sub
'
Private Sub CommandButton1_Click()
Dim Crit As String
Crit = CriteriosCtls
If Crit <> "" Then _
CoincidenciasDatos (Crit)
End Sub

bueno, no se como lo veras, pero en cualquier caso, lo mismo le resulta util
a alguien mas
(OJO a los posibles saltos de linea en el foro)

un saludo y hasta pronto
Ivan

PD: gracias de nuevo a Hector Miguel, que seguramente se dara una vuelta por
aqui (dudo que se le/te pase ningun mensaje del foro). Y si tanto el/tu como
cualquiera quiere comentar/enmendar algo de los codigos sera bien recibido
#15 Ivan
19/05/2007 - 03:02 | Informe spam
hola de nuevo,

como siempre aqui sigo con mis autohilos.

pero bueno, al fin y al cabo, alguien puede tirar de los codigos y resulta
que en estos ultimos codigos expuestos hay (que yo haya visto) al menos una
pega/fuga.

Se trata de la evaluacion en el filtro de los numeros decimales en caso de
no coincidir la configuracion regional del aparato con el 'punto UScentric'
Mostrar la cita
llevo todo el santo dia dandole vueltas y a puntito de mandar mil veces una
consulta sobre el tema. Le he dado vueltas a CDbl, CCur, tanto al dato
extraido del textbox, como al campo a comparar de la tabla.

al final la cosa parece funcionar con Replace. Supongo que como es para
pasarselo al filtro como criterio en forma de formula, y desde vba hay que
pasarselo con el punto aunque automaticamente en la hoja lo transforme en
coma, pues es lo suyo.

Aunque lo que me llama la atencion es que si lo escribia directamente con el
punto en el textbox (y sin usar replace, claro) no me lo reconocia, y en la
mayoria de mis intentos con conversores tampoco.

Las unicas formas de conseguirlo han sido: convirtiendo a texto ( y solo con
trim, con cstr o str tampoco lo consideraba igual) el campo a comparar con
el textbox

+o- asi: -> criterio = "=Trim(g2)=" & textbox5.Text

o mediante replace -> "=g2=" & replace(textbox5.text, Sep, ".")

donde Sep es el separador del sistema en la configuracion regional.

bueno disculpad el rollo, y si Hector, o cualquier otro leis este mensaje y
podeis ampliar informacion al respecto (aunque en lo que respecta a Hector
M. creo que ya me ha dado mas de una vez consejos al respecto, pero creo que
soy un ¿poco? zoquete)

en cualquier caso este es el codigo de CriteriosCtls modificado, que
permite introducir decimales en el ultimo textbox (correspondiente a
importe) con la coma como separador ( y creo que con cualquier otra
configuracion). He quitado los comentarios pero siguen siendo validos los
mismos del anterior.

Function CriteriosCtls() As String
Dim nCt As Long, Valor As Long, Fecha As Long, _
strCriterio As String, strControles As String, _
Operador, Ini As Long, Fin As Long, Sep As String
strControles = "TextBox1 TextBox2 ComboBox1 " & _
"ComboBox2 TextBox3 TextBox4 " & _
"ComboBox3 ComboBox4 TextBox5"
Operador = Array("a2>=", "a2<=", "b2=", "c2=", _
"d2>=", "d2<=", "e2=", "f2=", "g2=")
strCriterio = "": Valor = 0: Fecha = 0
Sep = Application.International(xlDecimalSeparator)
Ini = LBound(Split(strControles))
Fin = UBound(Split(strControles))
For nCt = Ini To Fin
With Me.Controls(Split(strControles)(nCt))
If Trim(.Text) <> "" Then
Select Case nCt
Case Is = Ini
If IsNumeric(.Text) Then
Valor = CLng(.Text)
strCriterio = Operador(nCt) & Valor & ","
End If
Case Is = Ini + 1
If IsNumeric(.Text) Then
If CLng(.Text) > Valor Then Valor = CLng(.Text)
strCriterio = strCriterio & Operador(nCt) & Valor & ","
End If
Case Is = Ini + 4
If IsDate(.Text) Then
Fecha = CLng(CDate(.Text))
strCriterio = strCriterio & Operador(nCt) & Fecha & ","
End If
Case Is = Ini + 5
If CLng(CDate(.Text)) > Fecha Then
Fecha = CLng(CDate(.Text))
strCriterio = strCriterio & Operador(nCt) & Fecha & ","
End If
Case Is = Fin
If IsNumeric(.Text) Then strCriterio = strCriterio & _
Operador(nCt) & Replace(.Text, Sep, ".") & ","
Case Else
strCriterio = strCriterio & Operador(nCt) & """" & Trim(.Text) &
"""" & ","
End Select
End If
End With
Next
If strCriterio <> "" Then _
CriteriosCtls = "=and(" & Left(strCriterio, Len(strCriterio) - 1) &
")"
End Function


bueno, creo que va un poco mejor, y lo dicho si alguien se anima a comentar,
por aqui andamos

un saludo y hasta pronto
Ivan
Ads by Google
Search Busqueda sugerida