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

#1 Ivan
26/04/2007 - 02:27 | Informe spam
hola Mariano,

lo 1º una pregunta (aunque no estoy del todo seguro de haberte entendido
bien): ¿tienes algun campo unico(sin datos repetidos) en la tabla? por tu
anterior consulta creo entender que si, que no puede haber dos talones con
el mismo nº aunque en el resto de los campos se repitieran algunos.

si esto es asi, te comentoa algunas cosas:

1.- quizas ya lo estes haciendo, pero puedes 'sincronizar' el llenado de
todos los controles para que se llenen/muestren automaticamente en todos
ellos los campos correspondientes al introducir el nº de talon.

una forma de hacerlo es crear una matriz de 'nombres' de controles (o usar
un rango de celdas) en el mismo orden que tienen los registros
correspondientes y usar la propiedad controls del userform para rellenarlos.
Puedes hacer algo parecido a esto (no pongo tus controles, sino al tuntun):

sub PruebaSinChecar()
Dim c as byte, f as Long, MisCtls as variant, celda as range
MisCtls = Array("Textbox2", "Textbox3", "Textbox4", "ComboBox1",
"ComboBox2")
With <TuHoja>
if .[a22]="" then exit sub
for each celda in .range("a1:a" & .[a65536].end(xlup).row
If celda < nroTalon and nroTalon <= celda + 50 then
f = celda.row
for c = 0 to Ubound(MisCtls)
Me.Controls(c).Text = celda(1,c+1).value
next
exit sub
end if
next
end with
msgbox "No se ha encontrado el valor buscado"
end sub

en cuanto al reporte, una vez obtenida la fila de origen de los datos, no
deberias tener ningun problema. Un ej. podria ser algo asi:

With Worksheets("TuHojaDeDestino")
Worksheets("TuHojaDeOrigen").Range("a" & fila).EntireRow:Copy
.[a65536].end(xlup).Offset(1).PasteSpecial '<aqui los parametros que
quieras para pegar>
end with

nota: si los combos los llenas con todos los registros de la lista en el
mismo orden que estan, y en el momento de cargar el reporte se supone que el
item seleccionado en ellos es el correspondiente, puedes obtener el nº de
fila sumando el nº de la 1ª fila con datos de la hoja de origen (en el ej.
2, pues en la 1 irian los titulos) al listindex del combo -> f =
combo.ListIndex + 2

espero te sirva
un saludo
Ivan
Respuesta Responder a este mensaje
#2 Ivan
26/04/2007 - 02:46 | Informe spam
disculpa. se me olvidaba la 'mayor'

puedes crear una variable a nivel de modulo del formulario (o publica en un
modulo normal si la fueran a necesitar procedimientos que esten fuera del de
el formulario) y asignarle el valor de la fila cada vez que
busques/actualices un registro en el propio procedimiento de busqueda. Asi
la tendras disponible en cualquier momento para el reporte o para ..

un saludo
Ivan
Respuesta Responder a este mensaje
#3 Insumos
27/04/2007 - 00:07 | Informe spam
Ivan:

Primero que nada gracias por tu atención. Tus ideas son buenas. Incluso
habia empezado medio encaminado hacia ese lado cuando empezé a ver esto del
buscador. Pero me encontré con los escollos que te mencionaba. Tal vez, como
dices, se ve todo más claro en un ejemplo:
Supongamos (para simplificar) que en la hoja de mi base de datos tengo 3
campos y estos datos:

Número Compr. Sucursal Beneficiario
1 Buenos Aires Juan
2 Mar del Plata Juan
3 Buenos Aires Marcelo
4 Buenos Aires Juan
5 Mar del Plata Marcelo

Ahora, en un UserForm tengo un TextBox1 y un TextBox2 (para busca desde
Número hasta Número), un ComboBox1 (con las Sucursales) y un ComboBox2 (para
buscar el Beneficiario). Por último esta el Commnad Button1 que al hacer
click en el busca los registros que cumplan con lo especificado.

Ahora veamos estos casos:
A)
TextBox1 dice "1" y TextBox2 dice "3"
ComboBox1 está vacio (no se seleccionó nada)
ComboBox2 está vacio (no se seleccionó nada)
RESULTADO DEL CLICK EN EL COMMANDBUTTON1 = los registros con números 1, 2 y
3 (los que están entre 1 y 3 sin importar de que Sucursal sean o que
Beneficiario tengan)

B)
TextBox1 dice "1" y TextBox2 dice "3"
ComboBox1 dice Buenos Aires
ComboBox2 está vacio (no se seleccionó nada)
RESULTADO DEL CLICK EN EL COMMANDBUTTON1 = los registros con números 1 y 3
(los que estan entre 1 y 3 y son de la sucursal Buenos Aires, sin importar
el Beneficiario que sea)

C)
TextBox1 dice "1" y TextBox2 dice "3"
ComboBox1 dice Buenos Aires
ComboBox2 dice Marcelo
RESULTADO DEL CLICK EN EL COMMANDBUTTON1 = el registro con número 3 (los que
estan entre 1 y 3 y son de la sucursal Buenos Aires y además tienen a
Marcelo como Beneficiario)

D)
TextBox1 está vacio y TextBox2 está vacio
ComboBox1 dice Buenos Aires
ComboBox2 está vacio (no se seleccionó nada)
RESULTADO DEL CLICK EN EL COMMANDBUTTON1 = los registros con números 1, 3 y
4 (todos los que son de la Sucursal Buenos Aires)

E)
TextBox1 está vacio y TextBox2 está vacio
ComboBox1 está vacio (no se seleccionó nada)
ComboBox2 dice Marcelo
RESULTADO DEL CLICK EN EL COMMANDBUTTON1 = los registros con números 3 y 5
(todos los que tienen a Marcelo como Beneficiario)

Bueno, creo que ahora en el ejemplo se ve más claro. La idea seria algo
parecido a una consulta de Base de datos, pero en Excel por medio de un
UserForm. Luego, con los registros encontrados construye un reporte en una
hoja.
Bueno, espero haberme explicado mejor esta vez!!
Gracias por la atención. Todas las ideas son Bienvenidas!!
Saludos!

Mariano

"Ivan" escribió en el mensaje
news:
disculpa. se me olvidaba la 'mayor'

puedes crear una variable a nivel de modulo del formulario (o publica en


un
modulo normal si la fueran a necesitar procedimientos que esten fuera del


de
el formulario) y asignarle el valor de la fila cada vez que
busques/actualices un registro en el propio procedimiento de busqueda. Asi
la tendras disponible en cualquier momento para el reporte o para ..

un saludo
Ivan


Respuesta Responder a este mensaje
#4 Ivan
28/04/2007 - 00:21 | Informe spam
hola Mariano,

aunque yo, particularmente (y es solo una opinión que tampoco tengo clara)
si estuviera en tu caso creo que aplicaría otro planteamiento (por ej.
sincronizar los controles (que según los cambios en ellos se fueran
filtrando las entradas en el resto/en la mayoría) e ir llenando/vaciando un
listbox con las coincidencias y cargar en el reporte cuando lo tuviera claro
en el listbox), si quieres échale un ojo al ej. que te pongo al final, creo
que hace mas o menos lo que buscas

ten en cuenta que es solo una idea de mecanismos que podrías usar, pero
tiene unos cuantos inconvenientes, el mas vistoso creo que es que necesita 3
hojas 'ocultas' para ejecutarse ( para este ej., para mas controles
requeriría mas, aunque también se podrían añadir sobre la marcha y
eliminarlas cuando acabe el proceso) aunque puliéndolo seguramente se podría
quedar en 2 o 1.

Otro 'pero' seria que requiere ir añadiendo código adicional con cada
control. Aquí seguramente se podría usar algo parecido a la matriz de
'nombres' que te comentaba, para realizar un bucle y trabajar solo sobre los
que contuvieran datos.

bueno, te explico el ej., que es bastante extenso en cuanto a código:

requisitos:

1º.- en un libro nuevo pon en la hoja1 en la columna A tu listado de
talones, en la B las ciudades (p. ej.) y en la C los clientes (como en tu
ejemplo) y completa el libro hasta que tenga al menos 5 hojas. En el ej. se
deberian llamar como veras en las constantes pero puedes cambiar el valor de
estas por el que quieras ponerle a tus hojas. Lo único asegurate que la
constante 'LISTA lleva el nombre de la hoja en la que tienes la base de
datos y la REPORTE la del ídem (en esta hoja asegurate de que al menos haya
datos/títulos en la celda A1), así como de que las otras 3 constantes se
corresponden con nombres validos/existentes

ojo->la hoja con la base de datos tiene que estar ordenada por la columna A
en forma ascendente ( si lo prefieres se lo puedes añadir vía código)

2º.- en el proyecto del libro inserta un userform y un modulo normal (este
ultimo puedes evitarlo y poner todos los códigos en el del userform, pero
poniéndolo en el normal podrás disponer de los códigos para otros procesos
de tu archivo).

3º.- inserta (sin cambiarles el nombre) en el form dos textbox, dos combos y
un commandbutton. Pega los códigos, dale a F5 y correte unas pruebas. Ojo:
no lleva control de errores de casi ningún tipo, así que intenta evitarlos
(sobre todo si introduces valores en los textbox, asegurate que sean
(parezcan, ...je,je...) números)

nota: como veras los códigos son muy mejorables/simplificables y alguna de
las funciones son mas bien 'Sub', pero por no cambiarlos... En fin échales
un ojo y a ver si te sirven para algo. No llevan casi explicaciones, pero
creo que son bastante evidentes. De todas formas con las dudas consulta y si
yo no lo se (cosa probable) ya aparecerá alguien.

un saludo y hasta pronto
Ivan

aquí va el ej.:

' en un modulo normal--

Option Explicit
' los codigos para filtrar (y...) estan basados en ayudas de
' Hector Miguel, del foro de Excel
'-
'' filtra los registros de la columna y de la hoja indicadas
'' era sobre todo para llenar un combo con los registros
'' unicos de la columna elegida en otro
'' para que los registros se carguen ordenados
'' desmarcar el ultimo comentario (en este caso no es necesario,
'' pues la lista tiene que estar ordenada previamente)
'
Public Function Filtrar_Columna(ByVal hj_Bsq As String, _
ByVal col_Bsq As Long)
Dim Lt_Col As String
With Worksheets(hj_Bsq)
If .[a2] = "" Then MsgBox _
"En la lista de busqueda no hay ningun dato.": Exit Function
Lt_Col = Chr(64 + col_Bsq)
If .AutoFilterMode Then .AutoFilterMode = False
.[iv:iv].Clear
.Columns(Lt_Col).AdvancedFilter xlFilterCopy, , .[iv1], True
' .[iv:iv].Sort key1:=.[iv2], order1:=xlAscending, header:=True
End With
End Function
'-
'' filtra una hoja pasada por un dato y el nº de columna
'' y pega los datos filtrados en otra hoja
'
Public Function Filtrar_Lista(ByVal hj_Bsq As String, _
ByVal hj_Oct As String, ByVal d_Patron As String, _
ByVal Campo_B As Long, ByRef No_Buscar As Boolean)
With Worksheets(hj_Bsq)
If .[a2] = "" Then
MsgBox "En la lista de busqueda no hay ningun libro."
No_Buscar = True
Exit Function
End If
Worksheets(hj_Oct).UsedRange.EntireRow.Delete
If .AutoFilterMode Then .AutoFilterMode = False
.UsedRange.AutoFilter
If .AutoFilterMode Then _
.Range("a1").CurrentRegion.AutoFilter _
Field:=Campo_B, _
Criteria1:=d_Patron
With .AutoFilter.Range
If .Rows.Count > 1 Then
On Error Resume Next
.SpecialCells(xlCellTypeVisible) _
.Copy Worksheets(hj_Oct).Range("a1")
On Error GoTo 0
Else
.AutoFilterMode = False
No_Buscar = True
Exit Function
End If
End With
If .AutoFilterMode Then .AutoFilterMode = False
End With
End Function
'
'' para iniciar el filtrado de datos solo
'' entre los registros que esten entre dos
'' valores dados (los copia a otra hoja)
'
Public Function Copiar_Intervalo( _
ByVal hjOrigen As String, _
ByVal hjOculta As String, _
ByVal n1 As Long, _
ByVal n2 As Long, _
ByRef nroUnico As Boolean) As Boolean
Dim fUlt As Long, fi1 As Long, fi2 As Long, rango As Range
With Worksheets(hjOrigen)
If .[a2] = "" Then Exit Function
If n1 = 0 And n2 = 0 Then Exit Function
fUlt = .[a65536].End(xlUp).Row
With .Range("a1:a" & fUlt)
On Error Resume Next
If n1 <> 0 Then _
fi1 = .Find(n1, .Cells(1, 1), _
xlFormulas, xlWhole).Row
If n2 <> 0 Then _
fi2 = .Find(n2, .Cells(1, 1), _
xlFormulas, xlWhole).Row
On Error GoTo 0
End With
If fi1 = 0 And fi2 = 0 Then Exit Function
Select Case n2 - n1
Case Is < 0, Is = 0
Set rango = .Range("a" & fi1): nroUnico = True
Case Is = n2
Set rango = .Range("a" & fi2): nroUnico = True
Case Else
Set rango = .Range("a" & fi1 & ":a" & fi2)
End Select
End With
With Worksheets(hjOculta)
.UsedRange.EntireRow.Delete
.[a1:c1] = Array("Nro", "Ciudad", "Cliente")
rango.EntireRow.Copy .[a2]
End With
Set rango = Nothing
Copiar_Intervalo = True
End Function

'-en el modulo del formulario
'
Option Explicit
Dim SoloUnDato As Boolean, HayDatos As Boolean
Private Const LISTA As String = "Hoja1"
Private Const OCULTA_1 As String = "Hoja2"
Private Const OCULTA_2 As String = "Hoja3"
Private Const OCULTA_3 As String = "Hoja4"
Private Const REPORTE As String = "Hoja5"

Private Sub CommandButton1_Click()
Dim fUlt As Long
If Not HayDatos And ComboBox1.Text = "" And _
ComboBox2.Text = "" Then Exit Sub
Application.ScreenUpdating = False
With Worksheets(OCULTA_3)
.UsedRange.EntireRow.Delete
If SoloUnDato Then
Worksheets(OCULTA_1).[a2].EntireRow.Copy
.[a65536].End(xlUp).Offset(1).PasteSpecial xlPasteAll
Else
If Not HayDatos Then
With Worksheets(OCULTA_1)
.UsedRange.EntireRow.Delete
Worksheets(LISTA).UsedRange.Copy
.[a1].PasteSpecial xlPasteAll
End With
End If
With Worksheets(OCULTA_2)
.UsedRange.EntireRow.Delete
Worksheets(OCULTA_1).UsedRange.Copy
.[a1].PasteSpecial xlPasteAll
End With
With ComboBox1
If .Text <> "" Then Filtrar_Lista OCULTA_1, OCULTA_2, .Text, 2,
HayDatos
End With
With ComboBox2
If .Text <> "" Then
Filtrar_Lista OCULTA_2, OCULTA_3, .Text, 3, HayDatos
Else
With Worksheets(OCULTA_3)
.UsedRange.EntireRow.Delete
Worksheets(OCULTA_2).UsedRange.Copy
.[a1].PasteSpecial xlPasteAll
End With
End If
End With
End If
If .[a2] = "" Then MsgBox "No hay coincidencias": Exit Sub
fUlt = .[a65536].End(xlUp).Row
.Range("a2:a" & fUlt).EntireRow.Copy
Worksheets(REPORTE).[a65536].End(xlUp).Offset(1).PasteSpecial
xlPasteValues
End With
Unload Me
End Sub

Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Dim nro1 As Long, nro2 As Long
If TextBox1 = "" Then nro1 = 0 Else nro1 = CLng(TextBox1)
If TextBox2 = "" Then nro2 = 0 Else nro2 = CLng(TextBox2)
HayDatos = Copiar_Intervalo(LISTA, OCULTA_1, nro1, nro2, SoloUnDato)
End Sub


Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Dim nro1 As Long, nro2 As Long
If TextBox1 = "" Then nro1 = 0 Else nro1 = CLng(TextBox1)
If TextBox2 = "" Then nro2 = 0 Else nro2 = CLng(TextBox2)
HayDatos = Copiar_Intervalo(LISTA, OCULTA_1, nro1, nro2, SoloUnDato)
End Sub

Private Sub UserForm_Initialize()
Filtrar_Columna LISTA, 2
With Worksheets(LISTA)
If .[iv2] = "" Then Exit Sub
ComboBox1.List = .Range("iv2:iv" & .[iv65536].End(xlUp).Row).Value
Filtrar_Columna LISTA, 3
If .[iv2] = "" Then Exit Sub
ComboBox2.List = .Range("iv2:iv" & .[iv65536].End(xlUp).Row).Value
End With
End Sub
Respuesta Responder a este mensaje
#5 Ivan
28/04/2007 - 03:11 | Informe spam
hola de nuevo, Mariano

en los codigos que te he mandado antes, si te decides a probarlos, cambia
todo el codigo del formulario por este otro, que de momento parece que
corrige casi todos los fallos que tenia el otro :

OJO a los saltos de linea del foro

Option Explicit
Private Const LISTA As String = "Hoja1"
Private Const OCULTA_1 As String = "Hoja2"
Private Const OCULTA_2 As String = "Hoja3"
Private Const OCULTA_3 As String = "Hoja4"
Private Const REPORTE As String = "Hoja5"
Sub SinCoincidencias()
MsgBox "No hay coincidencias"
End Sub
Sub SinDatos()
MsgBox "No has introducido ningun dato"
End Sub
Private Sub CommandButton1_Click()
Dim fUlt As Long, unico1 As Boolean, unico2 As Boolean, _
HayDatos As Boolean, SoloUnDato As Boolean, _
nro1 As Long, nro2 As Long
Worksheets(OCULTA_1).UsedRange.EntireRow.Delete
Worksheets(OCULTA_2).UsedRange.EntireRow.Delete
Worksheets(OCULTA_3).UsedRange.EntireRow.Delete
Application.ScreenUpdating = False
If Trim(TextBox1.Text) = "" And Trim(TextBox2.Text) = "" Then
If ComboBox1.Text = "" And _
ComboBox2.Text = "" Then: SinDatos: Exit Sub
With Worksheets(OCULTA_1)
Worksheets(LISTA).UsedRange.Copy
.[a1].PasteSpecial xlPasteAll
End With
Else
If Trim(TextBox1.Text) = "" Then nro1 = 0 Else nro1 = CLng(TextBox1)
If Trim(TextBox2.Text) = "" Then nro2 = 0 Else nro2 = CLng(TextBox2)
HayDatos = Copiar_Intervalo(LISTA, OCULTA_1, nro1, nro2, SoloUnDato)
If Not HayDatos Then: SinCoincidencias: Exit Sub
End If
With Worksheets(OCULTA_3)
If SoloUnDato Then
With Worksheets(OCULTA_1)
If ComboBox1.Text = "" Then unico1 = True Else _
unico1 = Trim(.[b2].Value) = Trim(ComboBox1.Text)
If ComboBox2.Text = "" Then unico2 = True Else _
unico2 = Trim(.[c2].Value) = Trim(ComboBox2.Text)
If unico1 And unico2 Then
.[a2].EntireRow.Copy
Worksheets(REPORTE).[a65536].End(xlUp) _
.Offset(1).PasteSpecial xlPasteValues
Unload Me
Else
SinCoincidencias
End If
End With
Exit Sub
Else
With Worksheets(OCULTA_1)
If .[a2] = "" Then
Worksheets(LISTA).UsedRange.Copy
.[a1].PasteSpecial xlPasteAll
End If
End With
If ComboBox1.Text <> "" Then Filtrar_Lista OCULTA_1, _
OCULTA_2, ComboBox1.Text, 2, HayDatos
With Worksheets(OCULTA_2)
If .[a2] = "" Then
Worksheets(OCULTA_1).UsedRange.Copy
.[a1].PasteSpecial xlPasteAll
End If
End With
If ComboBox2.Text <> "" Then
Filtrar_Lista OCULTA_2, OCULTA_3, _
ComboBox2.Text, 3, HayDatos
Else
Worksheets(OCULTA_2).UsedRange.Copy
.[a1].PasteSpecial xlPasteAll
End If
End If
If .[a2] = "" Then SinCoincidencias: Exit Sub
fUlt = .[a65536].End(xlUp).Row
.Range("a2:a" & fUlt).EntireRow.Copy
Worksheets(REPORTE).[a65536].End(xlUp) _
.Offset(1).PasteSpecial xlPasteValues
End With
Unload Me
End Sub

Private Sub UserForm_Initialize()
Filtrar_Columna LISTA, 2
With Worksheets(LISTA)
If .[iv2] = "" Then Exit Sub
ComboBox1.List = .Range("iv2:iv" & .[iv65536].End(xlUp).Row).Value
Filtrar_Columna LISTA, 3
If .[iv2] = "" Then Exit Sub
ComboBox2.List = .Range("iv2:iv" & .[iv65536].End(xlUp).Row).Value
End With
End Sub


un saludo
Ivan
Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente Respuesta Tengo una respuesta
Search Busqueda sugerida