使用ArcPy有效选择相关记录?


14

下面是我用来复制ArcMap中“相关表”按钮的代码。在ArcMap中,该按钮基于对另一个相关要素类或表中要素的选择来选择一个要素类或表中的要素。

在ArcMap中,我可以使用该按钮在几秒钟内将我的选择“推送”到相关表。我找不到arcpy内置的任何可复制按钮的内容,因此我使用了一些嵌套循环来完成相同的任务。

下面的代码遍历“处理”表。对于每种处理,它都会遍历“树”列表。当在处理的ID字段和树的ID字段中找到匹配项时,将在树层中进行选择。找到治疗的匹配项后,该代码将不会继续在树层中搜索其他匹配项。它返回到处理表,选择下一个处理,然后再次搜索树要素类。

该代码本身可以正常工作,但是非常缓慢。在这种情况下,“治疗表”具有16,000条记录。“树”要素类具有60,000条记录。

当ESRI将选择从一个表推到另一个表时,还有另一种更有效的方法来重新创建ESRI所做的事情吗?我应该为表创建索引吗?注意:此数据存储在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

2
您正在使用ArcGIS 10.1吗?如果是这样,arcpy.da.SearchCursor可能比arcpy.SearchCursor快得多(也许是10倍)。另外,您可能要考虑使用Python字典。我怀疑这样的“密钥文件选择”可能会从此处
PolyGeo

您的Oracle SDE数据库是否偶然?
blah238

Answers:


12

首先,是的,您一定要确保在两个表上都索引了您的主键和外键字段。这使DBMS可以更有效地计划和执行针对这些字段的查询。

其次,您SelectLayerByAttribute_management在一个紧密的嵌套循环中调用(每棵树每次处理一次)。这是非常低效的,原因如下:

  • 据我所知,您不需要两个循环,一个循环嵌套在另一个循环中。一个就足够了。
  • 与典型的内置Python函数相比,地理处理函数是“块状的”,并且需要花费大量时间来调用。您应该避免在紧密循环中调用它们。
  • 一次要求一个记录/ ID将导致数据库往返更多。

而是重构代码,以便SelectLayerByAttribute_management仅调用一次构造了所有相关记录的位置子句即可。

我从其他答案中借用了一个函数,用于哪里子句构造逻辑,我想它看起来像这样:

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)

您可以这样称呼它: selectRelatedRecords(treatment_tv, tree_fl, "Facility_ID", "FACILITYID")

笔记:

  • 这使用arcpy.da.SearchCursor,仅在10.1可用。如@PolyGeo所述,这些游标比其前任(arcpy.SearchCursor)快得多。可以很容易地修改它以使用旧的SearchCursor:

    sourceIDs = set([row.getValue(sourceField) for row in arcpy.SearchCursor(sourceLayer, "", "", sourceField)])
  • 如果您的SDE地理数据库位于Oracle上,请注意IN链接答案中的函数中使用的语句限制为1000个元素。此答案中描述了一种可能的解决方案,但是您必须修改函数以将其拆分为多个1000长度的IN语句,而不是一个。


5

上面的解决方案对我来说非常有效,而且很快。使用上面的代码和其他文章中引用的代码,这就是我的构建方式:

# 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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.