首页 编程与开发 ArcPy ArcPy实用教程(含arcpy select by attribute详细解析)

ArcPy实用教程(含arcpy select by attribute详细解析)

作者: GIS研习社 更新时间:2025-08-25 14:48:18 分类:ArcPy

很多团队在做 ArcGIS 数据处理时,最费时的环节往往是“点开工具、写筛选条件、导出结果”的重复操作。作为 GIS 研发与教学的一员,我常被问到:怎样把这些“按属性筛选”的流程写成可靠的脚本,既保证结果一致,又能应对不同数据源的 SQL 差异?本指南将带你一步步搭建一个可复用、可扩展的方案。

ArcPy实用教程(含arcpy select by attribute详细解析)

是什么:ArcPy 与基于属性的选择

ArcPy 是 ArcGIS 的 Python 接口,核心是把地理处理工具以函数形式暴露出来,便于自动化。基于属性的选择本质上就是向数据源发送 SQL 表达式,得到满足条件的记录(要素)。在 ArcPy 中,常用的是 arcpy.management.SelectLayerByAttribute

  • 对象类型:操作对象是“图层或表视图”(layer/view),而非直接对要素类。
  • 选择方式:支持 NEW_SELECTION、ADD_TO_SELECTION、REMOVE_FROM_SELECTION、SUBSET_SELECTION、SWITCH_SELECTION 等。
  • 输出管理:选择集可直接用于后续工具(如 CopyFeatures)或继续叠加空间选择。

要点:先把要素类变成“图层”,再在图层上做选择;图层承载“选择集”这一状态。

为什么:脚本化的价值

  • 可重复与可追溯:同一脚本在不同地区或时间段复用,保证标准一致。
  • 性能更优:让数据库/数据源替你筛选,避免 Python 逐行循环。
  • 参数化与集成:轻松嵌入批处理、调度和模型构建器,形成生产流水线。

怎么做:最小可行流程

  1. 准备环境与工作空间。
  2. 将要素类构造成图层。
  3. 编写 SQL 表达式(使用 AddFieldDelimiters 防止字段名兼容性问题)。
  4. 执行选择并导出结果。
# 基础示例:价值>100000 且 分区=R1 的地块
import arcpy

arcpy.env.workspace = r"C:GISdemo.gdb"
arcpy.env.overwriteOutput = True

fc = "Parcels"
lyr = "Parcels_lyr"

# 确保图层存在的是最新状态
if arcpy.Exists(lyr):
    arcpy.management.Delete(lyr)

arcpy.management.MakeFeatureLayer(fc, lyr)

fld_land = arcpy.AddFieldDelimiters(fc, "LAND_VALUE")
fld_zone = arcpy.AddFieldDelimiters(fc, "ZONING")

where = f"{fld_land} > 100000 AND {fld_zone} = 'R1'"

arcpy.management.SelectLayerByAttribute(lyr, "NEW_SELECTION", where)
arcpy.management.CopyFeatures(lyr, "Parcels_R1_HighValue")
print(arcpy.GetCount_management(lyr)[0], "features selected")

提示:where 子句中,文本值要用单引号括起;数值不需要引号。

SQL 表达式要点与常见坑

  • 字段定界符:不同数据源对字段名的定界方式不同(如双引号、方括号)。统一用 arcpy.AddFieldDelimiters(dataset, field) 生成,避免手写。
  • 通配符:大多数数据源使用 %(多字符)、_(单字符)。个人地理数据库(.mdb)使用 *?
  • NULL:用 IS NULLIS NOT NULL;不要用 = NULL。
  • 日期:文件/企业地理数据库常用 date 'YYYY-MM-DD HH:MM:SS';个人地理数据库常用 #YYYY-MM-DD#;企业库需遵循各自 SQL 方言。
  • 大小写:是否区分大小写取决于数据源与区域设置;必要时统一大小写或用函数处理(企业库)。
  • 精度:浮点比较尽量使用范围(如 BETWEEN 或差值阈值),避免直接等于比较。
数据源字段定界符LIKE 通配日期字面量示例
文件地理数据库 (.gdb)通常为双引号(由 AddFieldDelimiters 处理)% / _date '2023-01-01'
企业地理数据库遵循底层 DBMS(建议用 AddFieldDelimiters)% / _依 DBMS(如 Oracle: DATE '2023-01-01')
个人地理数据库 (.mdb)[](由 AddFieldDelimiters 处理)* / ?#2023-01-01#
Shapefile (.shp)由 AddFieldDelimiters 处理% / _date '2023-01-01'
# 日期与 NULL 示例
fc = "Inspections"
lyr = "Inspections_lyr"
arcpy.management.MakeFeatureLayer(fc, lyr)

d_fld = arcpy.AddFieldDelimiters(fc, "INSPECT_DATE")
s_fld = arcpy.AddFieldDelimiters(fc, "STATUS")

# 选择 2023 年内且状态非空的记录(文件地理数据库语法)
where = (
    f"{d_fld} >= date '2023-01-01 00:00:00' AND "
    f"{d_fld} <  date '2024-01-01 00:00:00' AND "
    f"{s_fld} IS NOT NULL"
)
arcpy.management.SelectLayerByAttribute(lyr, "NEW_SELECTION", where)

选择类型与组合策略

  • NEW_SELECTION:首次选择或重置选择集。
  • SUBSET_SELECTION:在已有选择集内进一步筛选。
  • ADD_TO_SELECTION / REMOVE_FROM_SELECTION:并集或差集式操作。
  • SWITCH_SELECTION:反选,快速得到补集。
# 先按属性,再叠加空间关系进行“组合筛选”
roads = "Roads"
city = "CityBoundary"
rlyr = "Roads_lyr"

arcpy.management.MakeFeatureLayer(roads, rlyr)

# 1) 仅选主干道
fld = arcpy.AddFieldDelimiters(roads, "CLASS")
arcpy.management.SelectLayerByAttribute(rlyr, "NEW_SELECTION", f"{fld} = 'Primary'")

# 2) 再筛选位于城市边界内的主干道
arcpy.management.SelectLayerByLocation(
    rlyr, "INTERSECT", city, selection_type="SUBSET_SELECTION"
)

# 3) 导出
arcpy.management.CopyFeatures(rlyr, "PrimaryRoads_InCity")

性能优化与工程实践

  • 索引优先:对高频过滤字段建立属性索引;显著提升选择速度。
  • 一次建层,多次复用:MakeFeatureLayer 创建一次,后续多次选择,避免重复开销。
  • 充分用 SQL:能在 where 子句完成的过滤,不要用 Python 循环逐行判断。
  • 内存工作空间:临时结果可用 in_memory(注意容量与生命周期)。
  • 选择后直接串联:将选择集直接传给 CopyFeatures、CalculateField 等,减少磁盘 I/O。
  • 批处理:把 where 子句参数化,驱动多地区/多时间段自动跑批。
# 参数化批处理(简化示例)
def export_by_zone(workspace, fc, zone_value, out_name):
    arcpy.env.workspace = workspace
    lyr = "tmp_lyr"
    if arcpy.Exists(lyr):
        arcpy.management.Delete(lyr)
    arcpy.management.MakeFeatureLayer(fc, lyr)
    z = arcpy.AddFieldDelimiters(fc, "ZONING")
    where = f"{z} = '{zone_value}'"
    arcpy.management.SelectLayerByAttribute(lyr, "NEW_SELECTION", where)
    arcpy.management.CopyFeatures(lyr, out_name)
    return int(arcpy.management.GetCount(lyr)[0])

# 批量导出多个分区
for z in ["R1", "R2", "C1"]:
    n = export_by_zone(r"C:GISdemo.gdb", "Parcels", z, f"Parcels_{z}")
    print(z, ":", n)

与 Data Access 游标的配合

当仅需读取统计或做轻量计算时,arcpy.da 游标支持 where_clause,能不创建图层而直接过滤。

# 使用 SearchCursor 按属性过滤后统计数量
fc = r"C:GISdemo.gdbParcels"
fld_val = arcpy.AddFieldDelimiters(fc, "LAND_VALUE")
where = f"{fld_val} > 100000"

cnt = 0
with arcpy.da.SearchCursor(fc, ["OID@", "LAND_VALUE"], where_clause=where) as cur:
    for oid, val in cur:
        cnt += 1
print("count:", cnt)

选择集与游标并不冲突:前者适合串联地理处理工具;后者适合轻量读写与自定义逻辑。

典型案例与可复用片段

# 1) 模糊匹配:名称以 'San' 开头(% 为任意多字符)
fc = "Counties"; lyr = "Counties_lyr"
arcpy.management.MakeFeatureLayer(fc, lyr)
name_f = arcpy.AddFieldDelimiters(fc, "NAME")
arcpy.management.SelectLayerByAttribute(lyr, "NEW_SELECTION", f"{name_f} LIKE 'San%'")
arcpy.management.CopyFeatures(lyr, "Counties_SanPrefix")

# 2) 复合条件:人口>10万 且 面积在[500, 2000]
pop_f = arcpy.AddFieldDelimiters(fc, "POP")
area_f = arcpy.AddFieldDelimiters(fc, "AREA_KM2")
where = f"{pop_f} > 100000 AND {area_f} BETWEEN 500 AND 2000"
arcpy.management.SelectLayerByAttribute(lyr, "NEW_SELECTION", where)

# 3) 处理空值:仅保留代码不为空的记录
code_f = arcpy.AddFieldDelimiters(fc, "CODE")
arcpy.management.SelectLayerByAttribute(lyr, "SUBSET_SELECTION", f"{code_f} IS NOT NULL")
数据源 → MakeFeatureLayer → SelectLayerByAttribute → (可选)SelectLayerByLocation → CopyFeatures/统计
基于属性选择的通用流水线

结语

本文从“是什么/为什么”切入,落到“怎么做”的操作层:用图层承载选择集,用 AddFieldDelimiters 适配不同数据源方言,用标准 SQL 处理字符串、日期与 NULL,选择类型组合实现复杂筛选,并配合游标、索引与内存工作空间优化性能。掌握这些要点,你就能把任何一次性的手工筛选变为稳定的自动化构件。

你的数据源类型和典型 where 子句有哪些?欢迎把代表性的表达式与难点留言交流。我是 Dr.gis,也欢迎关注 GIS研习社(gisyxs.com) 的进阶实战内容。

参考文献

  • ArcGIS Pro: Select Layer By Attribute (Data Management)
  • ArcGIS Pro: SQL reference for query expressions used in ArcGIS
  • ArcPy: AddFieldDelimiters
  • ArcPy Data Access: SearchCursor
  • ArcGIS Pro: Make Feature Layer
  • ArcGIS Pro: Select Layer By Location
相关文章