14 votos

¿Cómo puedo más eficiente seleccionar registros relacionados?

A continuación está el código que estoy usando para replicar las "tablas relacionadas" botón en ArcMap. En ArcMap que botón se selecciona características en una clase de entidad o tabla se basa en la selección de características en una clase de entidad o tabla.

En ArcMap puedo usar ese botón para "empujar" mi selección a la tabla relacionada en cuestión de segundos. Yo era incapaz de encontrar algo integrado en arcpy que replica el botón de lo que he usado algunos bucles anidados para realizar la misma tarea.

El código de abajo bucles a través de una tabla de "tratamientos". Para cada tratamiento, se repite a través de una lista de "los árboles". Cuando se encuentra una coincidencia entre la IDENTIFICACIÓN de los campos de tratamiento y árboles, una selección que se produce en el árbol de capas. Una vez que se encuentra una coincidencia para un tratamiento, el código no continuar la búsqueda del árbol de la capa adicional de los partidos. Se remonta a la mesa de tratamiento, selecciona el siguiente tratamiento y de nuevo busca a través del árbol de la clase de entidad.

El código en sí funciona bien, pero es dolorosamente lento. El tratamiento de "tabla" en este caso ha de 16.000 registros. El "árbol" de la clase de entidad tiene 60.000.

Hay otra manera más eficiente para recrear lo ESRI está haciendo cuando se empuja la selección de una tabla a otra? Debo ser la creación de un índice de las tablas? NOTA: los datos se almacenan en un SDE.

 # Create search cursor to loop through the treatments
treatments = arcpy.SearchCursor(treatment_tv)
treatment_field = "Facility_ID"

for treatment in treatments:

    #Get ID of treatment
    treatment_ID = treatment.getValue(treatment_field)

    # Create search cursor for looping through the trees
    trees = arcpy.SearchCursor(tree_fl)
    tree_field = "FACILITYID"

    for tree in trees:

        # Get FID of tree
        tree_FID = tree.getValue(tree_field)

        if tree_FID == treatment_FID:
            query = "FACILITYID = " + str(tree_FID)
            arcpy.SelectLayerByAttribute_management(tree_fl, "REMOVE_FROM_SELECTION", query)
            break

12voto

auramo Puntos 161

En primer lugar, sí, usted definitivamente quiere asegurarse de que su principal y clave externa campos están indizadas en ambas tablas. Esto permite que el DBMS planificar y ejecutar consultas contra estos campos de manera mucho más eficiente.

En segundo lugar, usted está llamando SelectLayerByAttribute_management en un apretado, bucle anidado (una vez por árbol por tratamiento). Esto es altamente ineficiente, por varias razones:

  • Usted no necesita dos circuitos, uno anidado dentro del otro, para esto, como lo que puedo decir. Uno será suficiente.
  • Funciones de geoprocesamiento son "grueso" y tomar un montón de tiempo para llamar en comparación con los típicos construido en Python las funciones. Usted debe evitar llamar a ellos en un bucle ajustado.
  • Preguntando por un registro/IDENTIFICACIÓN de un tiempo resulta en mucho más viajes de ida y vuelta a la base de datos.

En su lugar, refactorizar el código para que llame a SelectLayerByAttribute_management sólo una vez con un whereclause construido para seleccionar todos los registros relacionados.

Préstamo de una función desde otra respuesta para la whereclause construcción lógica, me imagino que se vería algo como esto:

def selectRelatedRecords(sourceLayer, targetLayer, sourceField, targetField):
    sourceIDs = set([row[0] for row in arcpy.da.SearchCursor(sourceLayer, sourceField)])
    whereClause = buildWhereClauseFromList(targetLayer, targetField, sourceIDs)
    arcpy.AddMessage("Selecting related records using WhereClause: {0}".format(whereClause))
    arcpy.SelectLayerByAttribute_management(targetLayer, "NEW_SELECTION", whereClause)

Se le puede llamar así: selectRelatedRecords(treatment_tv, tree_fl, "Facility_ID", "FACILITYID")

Notas:

  • Este sistema utiliza una arcpy.da.SearchCursor, sólo disponible en la versión 10.1. Como @PolyGeo se mencionó, estos cursores son mucho más rápidos que sus predecesores (arcpy.SearchCursor). Podría ser fácilmente modificado para usar el viejo SearchCursor a pesar de que:

    sourceIDs = set([row.getValue(sourceField) for row in arcpy.SearchCursor(sourceLayer, "", "", sourceField)])
    
  • Si la geodatabase SDE es en Oracle, se advierte que la IN instrucción utiliza en la función de los enlaces de respuesta es limitada a 1000 elementos. Una posible solución se describe en esta respuesta, pero usted tendría que modificar la función para que se dividió en varias 1000-longitud IN declaraciones en lugar de uno.

5voto

KAPes Puntos 798

La solución funciona muy bien para mí y fue muy rápido. Utilizando el código anterior y hace referencia código en el otro post de esto es cómo yo lo construyó:

# Local Variables
OriginTable = "This must be a Table View or Feature Layer"
DestinationTable = "This must be a Table View or Feature Layer"
PrimaryKeyField = "Matching Origin Table Field"
ForiegnKeyField = "Matching Destination Table Field"

def buildWhereClauseFromList(OriginTable, PrimaryKeyField, valueList):
  """Takes a list of values and constructs a SQL WHERE
       clause to select those values within a given PrimaryKeyField
       and OriginTable."""

    # Add DBMS-specific field delimiters
    fieldDelimited = arcpy.AddFieldDelimiters(arcpy.Describe(OriginTable).path, PrimaryKeyField)

    # Determine field type
    fieldType = arcpy.ListFields(OriginTable, PrimaryKeyField)[0].type

    # Add single-quotes for string field values
    if str(fieldType) == 'String':
    valueList = ["'%s'" % value for value in valueList]

    # Format WHERE clause in the form of an IN statement
    whereClause = "%s IN(%s)" % (fieldDelimited, ', '.join(map(str, valueList)))
    return whereClause

def selectRelatedRecords(OriginTable, DestinationTable, PrimaryKeyField, ForiegnKeyField):
    """Defines the record selection from the record selection of the OriginTable
      and applys it to the DestinationTable using a SQL WHERE clause built
      in the previous defintion"""

    # Set the SearchCursor to look through the selection of the OriginTable
    sourceIDs = set([row[0] for row in arcpy.da.SearchCursor(OriginTable, PrimaryKeyField)])

    # Establishes the where clause used to select records from DestinationTable
    whereClause = buildWhereClauseFromList(DestinationTable, ForiegnKeyField, sourceIDs)

    # Process: Select Layer By Attribute
    arcpy.SelectLayerByAttribute_management(DestinationTable, "NEW_SELECTION", whereClause)

# Process: Select related records between OriginTable and DestinationTable
selectRelatedRecords(OriginTable, DestinationTable, PrimaryKeyField, ForiegnKeyField)

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X