Access, Consultas - Número de Dependencias de un elemento dentro de una organización en Árbol

Tengo en Access dos tablas; en una de ellas tengo todos los elementos y en otra tabla la dependencia entre ellos a través de 2 columnas (elemento A depende de elemento B).

Necesito obtener el nº de dependencias hasta el origen de la fuente, o en otras palabras, el nº de elementos que está por encima de cada elemento.

Tengo hecha una programación en VBA que me cuenta el número de elementos que está por encima de cada elemento pero me tarda mucho... Me gustaría saber si lo puedo hacer con una consulta nativa más ligera para que además cualquiera pueda abrirla y consultar el nivel de dependencias.

Como una imagen vale más que mil palabras os paso una idea (por favor tened en cuenta que puedo tener muchos más niveles 0 y bastantes más niveles que 3);

Cualquier ayuda es de agradecer.

Respuesta
3

Pues yo discrepo contigo, en Access sí puedes hacer consultas recurrentes, añadiendo las veces que sean necesarias la misma tabla y vinculándola consigo misma.

Un ejemplo similar sería un árbol genealógico. En el foro Dudas Access Foro, planteamos hace un tiempo un reto sobre ese tema, y puedes bajar las soluciones que se dieron, a ver si te dan una idea de por dónde tirar: https://nksvaccessolutions.com/Foro/viewtopic.php?f=17&t=1090

La solución de Javi Terán se basa prácticamente en consultas, mientras que la de Javier Mil, en VBA.

Además puedes ojear también el ejemplo de Neckkito de árbol genealógico: http://neckkito.xyz/nck/index.php/ejemplos/20-especiales/215-arbol-genealogico

Perdona, no me expresé bien, en Access se pueden hacer consultas recurrentes cuando conoces el número de dependencias, pero en mi caso lo desconozco y es muy variable. Hasta donde sé, esta es la parte a la que me refiero que no se podría hacer en Access nativo, sino que es necesario un código VBA que itere.

Voy a echar un ojo a los ejemplos de Javier Mil y Nekkito. Cuando pueda público el mío porque creo que funciona bien, pero no está optimizado.

Muy agradecido por la ayuda!

Saludos

Si pones el código que tienes, puedo intentar "mejorarlo" (si se puede)

Muchas gracias! He publicado el código revisado dentro de mis respuestas de este hilo, ¿qué opinión te merecería? Gracias de nuevo!

2 respuestas más de otros expertos

Respuesta
3

Te voy a dar mi modesta opinión. Tal como pones en la imagen, no diferencias entre hijos, nietos bisnietos, etc.

Por otro lado, personalmente creo que es mucho más sencillo hacerlo con VB. Por ejemplo, supongamos que tengo una tabla Padres, con los nombres de personas

También tengo una tabla Hijos, vacía, exactamente igual(excepto que el campo Idelemento no es clave) que sólo me sirve como origen del subformulario, y luego se "borra"

Si construyo un formulario independiente, con un subformulario tabular basado en la tabla Hijos, donde en un combinado elijo un "padre"

Voy a elegir a Alejandra. En el cuadro de texto de la derecha, también independiente me aparece

Si en el combinado del subformulario, donde ya no me aparece Alejandra, ya que no se puede ser padre e hijo a la vez, voy eligiendo nombres

Es decir, en relación me aparece que Anabela es el primer hijo y Antonio el segundo de Alejandra.

Voy a elegir a Antonio

Es decir, Annette es el primer nieto de 1 y primer hijo de 2, etc.

Voy a elegir a Aria(no Stark)

Carine es el primer bisnieto de 1, primer nieto del segundo hijo de 1, etc.

Si ahora, en un combinado(donde sólo me aparecen los que tengan alguna relación), elijo uno cualquiera

Y como sabes quien es el 1, 1-2, 1-2-2, etc., utilizando Dlookup sabes quien corresponde a quien. O en vez de ponerlo así, poniendo el idelemento, etc.

El código del formulario Principal es

Private Sub Form_Close()
DoCmd.RunSQL "delete * from hijos"
End Sub
Private Sub IdElemento_AfterUpdate()
If IsNull(DLookup("relacion", "padres", "idelemento=" & Me.IdElemento & "")) Then
Relacion = IdElemento
Else
Relacion = DLookup("relacion", "padres", "idelemento=" & Me.IdElemento & "")
End If
DoCmd.RunSQL "update padres set relacion='" & Me.Relacion & "' where idelemento=" & Me.IdElemento & ""
DoCmd.RunCommand acCmdSaveRecord
End Sub

El código del subformulario es

Private Sub Nombre_AfterUpdate()
IdElemento = Me.Parent!IdElemento  El control Idelemento esta oculto
DoCmd.RunCommand acCmdSaveRecord
Relacion = Me.Parent!Relacion & "-" & Nz(DCount("*", "hijos", "idelemento=" & Me.IdElemento & ""))
DoCmd.RunSQL "update padres set relacion='" & Me.Relacion & "' where nombre like '" & Me.Nombre & "'"
End Sub
Private Sub Nombre_GotFocus()
Nombre.Requery
End Sub

Gracias Icue,

Es muy interesante. 

Mi código reordena cada vez que necesito obtener un dato ya que las relaciones y nos nombres van variando... Lo optimizaría si el código lo ejecuto al actualizar cada vinculación... Le voy a dar una vuelta en cuanto encuentre un tiempo y os paso mis conclusiones. Gracias!

Por cierto, feliz año a todos

Hola Icue, he publicado el código revisado dentro de mis respuestas de este hilo, ¿qué opinión te merecería?

Para conocer el nivel del elemento dentro del árbol que le corresponde, sería simplemente buscar el elemento dentro del campo ITEM y devolver el "Link_Level"

Gracias de nuevo!

Me parece perfecto. Aquí estamos para ayudarnos unos a otros.

Respuesta
1

He descubierto que Access no permite consultas reiterativas o recurrentes y hay que montarse un código VBA.

Creo que no la tengo bien montada por lo que tarda...

Encontré una posible solución a mi cuestión, comparto el codigo por si sirviera de ayuda a otros,

1) Solo trabajo con la tabla de las relaciones "LINKS"

2) En la tabla de relaciones tengo el campo para indicar el ITEM y el ITEM del que cuelga (ITEM_PARENT).

3) El nivel jerárquico lo traslado a las relaciones en lugar de a cada elemento. Es decir, habilito otro campo para indicar el nivel que la relación (Link_Level) tiene dentro del árbol que le corresponde (mi interés es que sea flexible).

La idea es que los ITEMs de los que cuelgan el resto de elementos sólo aparecen en el campo ITEM_PARENT.

Saludos

'resetear los ORDENES de los links:
    strSQL = "UPDATE LINKS SET Link_Level= 0"
    DoCmd.SetWarnings False
    CDB.Execute strSQL
    DoCmd.SetWarnings True
    'incrementar los niveles de los links dentro de la organización tipo arbol
    i = 0
    While DCount("*", "LINKS", "Link_Level= 0") > 0
        i = i + 1
        strSQL = "UPDATE LINKS" & _
                 " SET Link_Level= " & i & _
                 " WHERE Link_InternalProcedure = 0" & _
                 " AND ITEM_PARENT NOT IN(SELECT ITEM FROM LINKS WHERE Link_Level= 0)"
        DoCmd.SetWarnings False
        CDB.Execute strSQL
        DoCmd.SetWarnings True
    Wend

Perdonad, no sé cómo editar mi último mensaje, se me pasó adaptar una variable de mi código a algo genérico... lo edito.

'resetear los ORDENES de los links:
    strSQL = "UPDATE LINKS SET Link_Level= 0"
    DoCmd.SetWarnings False
    CDB.Execute strSQL
    DoCmd.SetWarnings True
    'incrementar los niveles de los links dentro de la organización tipo arbol
    i = 0
    While DCount("*", "LINKS", "Link_Level= 0") > 0
        i = i + 1
        strSQL = "UPDATE LINKS" & _
                 " SET Link_Level= " & i & _
                 " WHERE Link_Level= 0" & _
                 " AND ITEM_PARENT NOT IN(SELECT ITEM FROM LINKS WHERE Link_Level= 0)"
        DoCmd.SetWarnings False
        CDB.Execute strSQL
        DoCmd.SetWarnings True
    Wend

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas