Wybieranie funkcji według atrybutu na liście Python?

14

Próbuję dokończyć wybór według atrybutu w Pythonie, ale na podstawie zapytania, czy atrybut jest obecny na liście.

Takie zapytanie w najprostszej formie powinno być takie:

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

ale to podejście zwraca nieprawidłowy błąd wyrażenia.

W przeszłości musiałem używać bardziej skomplikowanej sytax dla tego typu zapytań, takich jak:

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

ale adaptacja tego fragmentu też nie wydaje mi się działać, tj .:

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

Czego tu brakuje?

jsnider
źródło

Odpowiedzi:

16

Twoje pierwotne zapytanie mogło zostać zmodyfikowane dla listy liczb całkowitych:

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

więc jeśli oid_list = [7, 9, 4, 8], to wynik jest następujący:

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

Należy pamiętać, że ta „sztuczka” działa, jeśli oid_listzawsze zawiera dwa lub więcej elementów, ponieważ inne prawidłowe krotki, takie jak ()lub (7,), spowodują błąd składni SQL.

Bardziej ogólne wyrażenie, które obsługiwałoby również zero lub jeden oid_listelement, to:

'"OBJECTID_1" IN ({0})'.format(', '.join(map(str, oid_list)) or 'NULL')
Mike T.
źródło
Nie zdawałem sobie sprawy, że interfejs wyboru ArcGIS obsługuje „IN”. Jest to prawdopodobnie bardziej wydajne niż moje rozwiązanie.
AHigh
1
Uważaj, istnieje górna granica obsługiwana przez zapytanie IN. Myślę, że to 2000 rekordów
Tristan Forward
9

Oto nieco zmodyfikowana wersja funkcji w tej odpowiedzi , aby zaakceptować listę Python zamiast łańcucha rozdzielanego średnikami:

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
źródło
6

Myślę, że najprostszym podejściem do tego jest iteracja pojedynczych wartości na liście i dodanie ich do zaznaczenia (aby można było zmienić zapytanie przy każdej wartości na liście). Coś takiego:

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)

Możesz użyć ADD_TO_SELECTION, nawet jeśli nie wybrano żadnych funkcji, utworzy nowy wybór przy pierwszej iteracji.

Edytować:

Jeśli uważasz, że koszt wykonania pojedynczego SelectLayerByAttribute będzie zbyt wysoki, możesz zastosować takie podejście, w którym tworzysz dość dużą klauzulę wyboru w zależności od długości listy:

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)
Wysokość
źródło
Ciekawy pomysł na iterację po wartościach i wykonanie wyboru według atrybutu dla każdej iteracji. Przetestuję to, ale jestem pewien, że to powinno zadziałać. Dzięki.
jsnider
wydaje się, że to działa, ale na pewno zajmie trochę czasu przetworzenie każdej selekcji dla dłuższych list.
jsnider
2
Zaktualizowałem odpowiedź, stosując inne podejście.
AHigh,
Dobry pomysł ze zaktualizowaną odpowiedzią. Wybrałem to podejście, ponieważ jest ono znacznie szybsze do przetwarzania większych list. Nieznacznie zmodyfikowano: q = "" dla x w oid_set: query = '"OBJECTID_1" =' + str (x) + 'OR' q = zapytanie q = q [1: -4], a następnie wybierz by atrybut. Wydaje się działać!
jsnider
Zaktualizuję moją odpowiedź z wybranym przez Ciebie podejściem, aby była przeanalizowana i łatwiejsza do odczytania. Cieszę się, że to zadziałało.
AHigh