การเลือกคุณสมบัติตามคุณสมบัติถ้าอยู่ในรายการ Python?


14

ฉันกำลังพยายามเลือกตามคุณลักษณะใน Python ให้เสร็จสิ้น แต่ขึ้นอยู่กับแบบสอบถามว่ามีแอตทริบิวต์อยู่ในรายการหรือไม่

แบบสอบถามที่ง่ายที่สุดควรเป็นดังนี้:

qry = " \"OBJECTID\" in oid_list"
arcpy.SelectLayersByAttribute_management(inft, "NEW_SELECTION", qry)

แต่วิธีการนั้นจะส่งกลับข้อผิดพลาดการแสดงออกที่ไม่ถูกต้อง

ก่อนหน้านี้ฉันต้องใช้ระบบที่ซับซ้อนมากขึ้นสำหรับการสืบค้นประเภทนี้เช่น:

sqlQuery2 = "nid in (" + ','.join(["'"+x+"'" for x in delta_list]) +")"

แต่การปรับตัวอย่างโค้ดนี้ก็ไม่ได้ผลสำหรับฉันเช่น:

 "OBJECTID_1 in (" + ','.join(["'"+str(x)+"'" for x in oid_list]) +")"

ฉันหายไปนี่อะไร

คำตอบ:


16

อาจมีการแก้ไขแบบสอบถามต้นฉบับของคุณสำหรับรายการจำนวนเต็ม:

'"OBJECTID_1" IN ' + str(tuple(oid_list))

ดังนั้นถ้าoid_list = [7, 9, 4, 8]ผลลัพธ์คือ:

"OBJECTID_1" IN (7, 9, 4, 8)

โปรดทราบว่า "เคล็ดลับ" นี้ใช้งานได้หากoid_listมีรายการสองรายการขึ้นไปเสมอเนื่องจากสิ่งอันดับอื่นที่ถูกต้องเช่น()หรือ(7,)จะส่งผลให้เกิดข้อผิดพลาดทางไวยากรณ์ของ SQL

นิพจน์ทั่วไปที่มากกว่าที่จะจัดการกับศูนย์หรือหนึ่งoid_listรายการจะเป็น:

'"OBJECTID_1" IN ({0})'.format(', '.join(map(str, oid_list)) or 'NULL')

ฉันไม่ทราบว่าส่วนต่อประสานการเลือก ArcGIS รองรับ 'IN' นี่อาจมีประสิทธิภาพมากกว่าโซลูชันของฉัน
AHigh

1
แค่ระวังมีขีด จำกัด สูงสุดที่ได้รับการสนับสนุนโดยแบบสอบถาม IN ฉันคิดว่ามันเป็น 2000 ระเบียน
อุโมงค์ไปข้างหน้า

9

นี่คือฟังก์ชันเวอร์ชันที่แก้ไขเล็กน้อยในคำตอบนี้เพื่อยอมรับรายการ Python แทนสตริงที่คั่นด้วยเครื่องหมายอัฒภาค:

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

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

    # Determine field type
    fieldType = arcpy.ListFields(table, field)[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

6

ฉันคิดว่าวิธีที่ตรงไปตรงมาที่สุดคือการวนซ้ำค่าต่างๆในรายการของคุณอย่างแปลกประหลาดและเพิ่มเข้าไปในการเลือก (เพื่อให้คุณสามารถเปลี่ยนแบบสอบถามของคุณด้วยค่าแต่ละค่าในรายการ) บางสิ่งเช่นนี้

oidList = [1,2,3,4]
arcpy.management.MakeFeatureLayer(thisFC,thisLyr)
for values in oidList:
    query = "\"OBJECTID\"="+str(values)
    arcpy.management.SelectLayerByAttribute(thisLyr,"ADD_TO_SELECTION",query)

คุณสามารถใช้ ADD_TO_SELECTION แม้ว่าจะไม่มีฟีเจอร์ที่เลือกก็ตามมันจะสร้างตัวเลือกใหม่ในการทำซ้ำครั้งแรก

แก้ไข:

หากคุณคิดว่าค่าใช้จ่ายในการทำ SelectLayerByAttribute แต่ละรายการนั้นสูงเกินไปคุณสามารถใช้วิธีการเช่นนี้ในที่ที่คุณสร้างส่วนคำสั่งที่มีขนาดใหญ่ขึ้นอยู่กับความยาวของรายการของคุณ:

oidList = [1,2,3,4]
arcpy.management.MakeFeatureLayer(thisFC,thisLyr)
query=""
q=""
oidList.sort()
for x in oidList:
    query="\"OBJECTID\"="+str(x)+" OR "+q
    q=query
q=q[1:-4]
arcpy.management.SelectLayerByAttribute(thisLyr,"NEW_SELECTION",q)

แนวคิดที่น่าสนใจในการวนซ้ำค่าต่างๆและดำเนินการเลือกตามแอตทริบิวต์สำหรับการทำซ้ำแต่ละครั้ง ฉันจะทดสอบสิ่งนี้ แต่ฉันค่อนข้างแน่ใจว่ามันควรจะใช้ได้ ขอบคุณ
jsnider

สิ่งนี้ดูเหมือนจะใช้งานได้ แต่จะต้องใช้เวลาในการประมวลผลการเลือกแต่ละรายการสำหรับรายการที่ยาวกว่า
jsnider

2
อัปเดตคำตอบด้วยวิธีการอื่น
AHigh

ความคิดที่ดีพร้อมคำตอบที่อัพเดต ฉันเลือกที่จะใช้วิธีการนี้เนื่องจากเร็วกว่ามากสำหรับการประมวลผลรายการขนาดใหญ่ แก้ไขเล็กน้อย: q = "" สำหรับ x ใน oid_set: query = '"OBJECTID_1" =' + str (x) + 'หรือ' q = คิวคิว q = q [1: -4] จากนั้นเลือกโดยการกระจายข้อมูล ดูเหมือนว่าจะทำงาน!
jsnider

ฉันจะอัปเดตคำตอบของฉันด้วยวิธีการที่คุณเลือกดังนั้นจึงมีการแยกวิเคราะห์และง่ายต่อการอ่าน ดีใจที่มันทำงาน
AHigh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.