Features nach Attribut auswählen, wenn in der Python-Liste?

13

Ich versuche, eine Auswahl nach Attribut in Python zu vervollständigen, jedoch basierend auf der Abfrage, ob ein Attribut in einer Liste vorhanden ist.

Eine solche Abfrage sollte im einfachsten Fall ungefähr so ​​lauten:

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

Dieser Ansatz gibt jedoch einen ungültigen Ausdrucksfehler zurück.

In der Vergangenheit musste ich für diese Art von Abfrage eine kompliziertere Systemsteuer verwenden, z. B .:

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

aber eine adaption dieses schnipsel scheint auch bei mir nicht zu funktionieren, dh:

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

Was vermisse ich hier?

jsnider
quelle

Antworten:

15

Ihre ursprüngliche Abfrage könnte für eine Liste von ganzen Zahlen geändert worden sein:

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

Wenn ja oid_list = [7, 9, 4, 8], dann ist das Ergebnis:

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

Beachten Sie, dass dieser "Trick" funktioniert, wenn oid_listimmer zwei oder mehr Elemente vorhanden sind, da andere gültige Tupel, wie z. B. ()oder (7,), zu einem SQL-Syntaxfehler führen.

Ein allgemeinerer Ausdruck, der auch null oder eins oid_listElemente behandeln würde, wäre:

'"OBJECTID_1" IN ({0})'.format(', '.join(map(str, oid_list)) or 'NULL')
Mike T
quelle
Ich habe nicht bemerkt, dass die ArcGIS-Auswahlschnittstelle 'IN' unterstützt. Dies ist wahrscheinlich effizienter als meine Lösung.
AHigh
1
Seien Sie nur vorsichtig, es gibt eine Obergrenze, die von der IN-Abfrage unterstützt wird. Ich denke, es sind 2000 Datensätze
Tristan Forward
9

Hier ist eine leicht geänderte Version der Funktion in dieser Antwort , um eine Python-Liste anstelle eines durch Semikolons getrennten Strings zu akzeptieren:

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
blah238
quelle
6

Ich denke, der einfachste Weg, dies zu tun, besteht darin, die Werte in Ihrer Liste einzeln zu durchlaufen und zur Auswahl hinzuzufügen (Sie können also Ihre Abfrage mit jedem Wert in der Liste ändern). Etwas wie das:

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)

Sie können ADD_TO_SELECTION verwenden, auch wenn keine Features ausgewählt sind. Bei der ersten Iteration wird eine neue Auswahl erstellt.

Bearbeiten:

Wenn Sie der Meinung sind, dass die Kosten für die Ausführung einzelner SelectLayerByAttribute-Befehle zu hoch sind, können Sie einen Ansatz wie diesen verwenden, bei dem Sie abhängig von Ihrer Listenlänge eine recht umfangreiche Auswahlklausel erstellen:

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)
Ein hoch
quelle
Interessante Idee, die Werte zu durchlaufen und für jede Iteration ein Auswahlattribut durchzuführen. Ich werde das testen, aber ich bin mir ziemlich sicher, dass dies funktionieren sollte. Vielen Dank.
Jsnider
Dies scheint zu funktionieren, wird aber sicherlich einige Zeit in Anspruch nehmen, um jede einzelne Auswahl für längere Listen zu verarbeiten.
Jsnider
2
Die Antwort wurde mit einem anderen Ansatz aktualisiert.
AHigh
Gute Idee mit der aktualisierten Antwort. Ich habe mich für diesen Ansatz entschieden, da er für die Verarbeitung größerer Listen viel schneller ist. Leicht modifiziert: q = "" für x in oid_set: query = '"OBJECTID_1" =' + str (x) + 'OR' q = query q = [1: -4] und dann selectbyattribute. Scheint zu funktionieren!
Jsnider
Ich werde meine Antwort mit Ihrem gewählten Ansatz aktualisieren, damit sie analysiert wird und leichter zu lesen ist. Ich bin froh, dass es funktioniert hat.
AHigh