Selezione delle caratteristiche per attributo se nell'elenco Python?


14

Sto cercando di completare una selezione per attributo in Python ma in base alla domanda se un attributo è presente in un elenco.

Una query del genere nella sua forma più semplice dovrebbe essere qualcosa del genere:

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

ma tale approccio restituisce un errore di espressione non valida.

In passato, ho dovuto usare una sintassi più complicata per questo tipo di query, come ad esempio:

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

ma un adattamento di questo frammento non sembra funzionare neanche per me, vale a dire:

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

Cosa mi sto perdendo qui?

Risposte:


16

La tua query originale avrebbe potuto essere modificata per un elenco di numeri interi:

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

quindi se oid_list = [7, 9, 4, 8], allora il risultato è:

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

Tenere presente che questo "trucco" funziona se oid_listha sempre due o più elementi, poiché altre tuple valide, come ()o (7,), risulteranno con un errore di sintassi SQL.

Un'espressione più generica che gestisca anche zero o un oid_listelemento sarebbe:

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

Non mi ero reso conto che l'interfaccia di selezione ArcGIS supportasse 'IN'. Questo è probabilmente più efficiente della mia soluzione.
AHigh

1
Diffidate, c'è un limite superiore supportato dalla query IN, penso che sia 2000 record
Tristan Forward

9

Ecco una versione leggermente modificata della funzione in questa risposta , per accettare un elenco Python invece di una stringa delimitata da punto e virgola:

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

Penso che l'approccio più diretto a questo sia quello di scorrere singolarmente i valori nella tua lista e aggiungerli alla selezione (così puoi cambiare la tua query con ogni valore nella lista). Qualcosa come questo:

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)

Puoi utilizzare ADD_TO_SELECTION anche se non ci sono funzionalità selezionate, creerà una nuova selezione alla prima iterazione.

Modificare:

Se ritieni che il costo per l'esecuzione di SelectLayerByAttribute individuale sia troppo elevato, potresti utilizzare un approccio come questo in cui crei una clausola di selezione piuttosto ampia a seconda della lunghezza dell'elenco:

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)

Interessante idea di scorrere i valori ed eseguire una selezione per attributo per ogni iterazione. Lo proverò, ma sono abbastanza sicuro che dovrebbe funzionare. Grazie.
jsnider,

questo sembra funzionare, ma avrà sicuramente del tempo per elaborare ogni singola selezione per elenchi più lunghi.
jsnider,

2
Aggiornato la risposta con un approccio diverso.
AHigh

Buona idea con la risposta aggiornata. Ho scelto di utilizzare questo approccio in quanto molto più veloce per l'elaborazione di elenchi più grandi. Leggermente modificato: q = "" per x in oid_set: query = '"OBJECTID_1" =' + str (x) + 'OR' q = query q = q [1: -4] e quindi selezionare per attributo. Sembra funzionare!
jsnider,

Aggiornerò la mia risposta con l'approccio scelto in modo che sia analizzato e più facile da leggere. Sono contento che abbia funzionato.
AHigh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.