Programmiertes Verbinden von Feldern in ArcMap?

9

Ist es möglich , die programmatisch zu identifizieren Join - Feld , der Tabelle zwei Datensätze zusammen in ArcMap Join verwendet wird? Ich verwende derzeit ArcGIS 10.0, SP5 und würde eine ArcPy-Lösung bevorzugen. Ich wäre jedoch nicht gegen andere Lösungen, wenn eine ArcPy-Lösung nicht verfügbar ist.

Eine Methode, die ich ausprobiert habe, bestand darin, alle Felder zu durchlaufen und nach einem passenden "Basisnamen" zu suchen. Dies ist jedoch nur eine "fundierte Vermutung", bei der Sie hoffen, dass die Feldnamen in beiden Datenbanken gleich sind.

Für eine grafische Darstellung dessen, wonach ich suche, möchte ich grundsätzlich das "Eingabe-Verknüpfungsfeld" und das "Ausgabe-Verknüpfungsfeld" identifizieren, wie im Dialogfeld "Verknüpfung hinzufügen" angezeigt, aber natürlich nachträglich.

Wie identifiziere ich das "Input Join Field" und das "Output Join Field"?

Dies ist eine Tag-On-Frage an Kann ein "Join" programmgesteuert erkannt werden? In diesem Fall möchte ich jedoch die Funktionalität erweitern, um die FELD (en) zu identifizieren, die zum Zusammenfügen der zwei (oder mehr) Datensätze verwendet werden.

RyanKDalton
quelle
Mit welcher Version von ArcGIS arbeiten Sie? Und ich gehe davon aus, dass Sie basierend auf den Tags speziell nach einer Möglichkeit suchen, dies mit arcpy und nicht mit ArcObjects zu tun?
blah238
Ich verwende derzeit ArcGIS 10.0, SP5. Und ja, ich suche / hoffe auf eine ArcPy-Lösung, aber ich wäre nicht gegen eine ArcObjects-Lösung, wenn dies die einzige Alternative ist.
RyanKDalton
1
Hier ist eine möglicherweise aufschlussreiche Dokumentation: edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/… Es handelt sich um die pRelClass. Dies ist die RelationshipClass, mit der die Verknüpfungstabellen und Verknüpfungsfelder sowie die Kardinalität definiert werden. Die Open-Methode erstellt entweder eine neue RelQueryTable oder gibt einen Verweis auf eine vorhandene RelQueryTable zurück, wenn diese Klasse bereits erstellt wurde. Sie können diese Methode aufrufen und die Referenz finden, die thepRelClass
lewis
@lewis, Sie müssen das Factory-Objekt nicht verwenden, um einen Verweis auf eine vorhandene RelQueryTable zu erhalten - siehe meine Antwort.
blah238

Antworten:

7

Im Folgenden finden Sie einen ArcObjects-Ansatz, der auf diesem Beispiel basiert , um alle Verknüpfungen auf einer Ebene aufzulisten und ihre Ziel- und Quelltabellennamen sowie Primär- und Fremdschlüssel aufzulisten:

  1. Holen Sie sich einen Verweis auf einen ILayer, der eine oder mehrere Verknüpfungen hat
  2. Wirf das ILayerzuIDisplayTable
  3. Cast die IDisplayTable.DisplayTableEigenschaft zuIRelQueryTable
  4. Während die aktuelle Tabelle ein IRelQueryTable:
    1. Überprüfen Sie die RelQueryTable‚s DestinationTableund SourceTableEigenschaften
    2. Überprüfen Sie die OriginPrimaryKeyund OriginForeignKeyEigenschaften der IRelQueryTable.RelationshipClassEigenschaft.
    3. Stellen Sie die aktuelle Tabelle der aktuellen RelQueryTable‚s - SourceTableEigenschaft

Das Python - Skript (mit comtypes und diese Helfer - Modul ) werden alle die Verknüpfungen gehen, von spätestens frühesten und die Ziel- und Quelltabellennamen drucken, Herkunft Primärschlüssel und Herkunft Fremdschlüssel für jeden Join:

from ESRICOMHelpers import * # helper module from https://gis.stackexchange.com/a/5082/753
esriArcMapUI = GetESRIModule("esriArcMapUI")
esriCarto = GetESRIModule("esriCarto")
esriGeoDatabase = GetESRIModule("esriGeoDatabase")

def listJoins(table):
    while CType(table, esriGeoDatabase.IRelQueryTable):
        relQueryTable = CType(table, esriGeoDatabase.IRelQueryTable)
        destTable = relQueryTable.DestinationTable
        sourceTable = relQueryTable.SourceTable
        destDataset = CType(destTable, esriGeoDatabase.IDataset)
        sourceDataset = CType(sourceTable, esriGeoDatabase.IDataset)
        relClass = relQueryTable.RelationshipClass
        print destDataset.Name, sourceDataset.Name, relClass.OriginPrimaryKey, relClass.OriginForeignKey
        table = sourceTable

if __name__ == "__main__":
    #app = GetCurrentApp() # Use if run in-process
    app = GetApp("ArcMap") # Use if run in a standalone script
    mxd = CType(app.Document, esriArcMapUI.IMxDocument)

    # Gets the first layer in the active data frame
    map = mxd.FocusMap
    lyr = map.Layer[0]

    # Need to get the "display table" to access the joins
    displayTable = CType(lyr, esriCarto.IDisplayTable).DisplayTable

    # List the layer's joined tables
    listJoins(displayTable)

Beispielausgabe bei einer Quellenebene mit drei Verknüpfungen:

join_table_3 master_fc_join_table_1_join_table_2 JOIN_ID_3 master_fc.MASTER_ID
join_table_2 master_fc_join_table_1 JOIN_ID_2 master_fc.MASTER_ID
join_table_1 master_fc JOIN_ID_1 MASTER_ID

Weitere Informationen finden Sie unter Wie greife ich von Python aus auf ArcObjects zu?

blah238
quelle
Das sieht sehr vielversprechend aus. Ich habe das comtypes-Paket installiert und den Hilfsfunktionscode hinzugefügt, aber ich erhalte den Fehler "global name 'esriGeoDatabase' is not defined". Wo / wie soll es im Code vor der Zeile definiert werden while CType(table, esriGeoDatabase.IRelQueryTable)?
RyanKDalton
Ich habe es nicht aufgenommen, aber irgendwann müssen Sie die comtypes-Wrapper um die spezifischen ESRI-Objektbibliotheken importieren, die Sie benötigen. Mit meinem Hilfsmodul ist es so einfach wie esriGeoDatabase = GetESRIModule("esriGeoDatabase").
blah238
Habe ich, danke. Funktioniert dies auch für Ebenen in ArcMap? Ich übergebe jede Ebene von layerList = arcpy.mapping.ListLayers(mxd)in den listJoins(table)Code, aber es wird bei der whileAnweisung übersprungen .
RyanKDalton
Ich glaube nicht, dass Sie zwischen arcpy-Objekten und comtypes-Objekten wechseln können, daher müssen Sie die ILayer-Referenz über ArcObjects erhalten. Ich habe den Code aktualisiert, um ein vollständigeres Beispiel aufzunehmen. Dies sollte sowohl innerhalb als auch außerhalb des Prozesses verwendet werden können, indem die relevanten Zeilen kommentiert / auskommentiert werden.
blah238
Näher dran, danke für die Geduld beim Durchgehen ... Wie haben Sie nun die eigentliche Kartendokumentdatei (* .mxd) gesendet, die Sie sich ansehen möchten? app.Documentkommt zurück mit'NoneType' object has no attribute 'Document'
RyanKDalton
1

Fügen Sie alle Daten der Felder in Zeichenfolgen ein (nachdem Sie sie bestellt haben), vergleichen Sie sie mit einer Fuzzy-Vergleichsfunktion und wählen Sie diejenigen aus, die die beste Übereinstimmung oder Übereinstimmung mit einer bestimmten Genauigkeit erzielt haben.

Diese Lösung ist, wenn einige Daten nicht passen würden. Wenn Sie der Meinung sind, dass beide Spalten immer passen, bestellen und vergleichen Sie einfach, um eine perfekte Übereinstimmung mit einer normalen Vergleichsfunktion zu erzielen.

Unter dem Radar
quelle
0

Versuche dies:

  • Verwenden Sie das XSLT-Transformationstool aus dem Metadaten-Toolset , um eine XML / HTML-Metadatendatei für das betreffende Dataset zu schreiben.

    arcpy.XSLTransform_conversion(r'X:\temp\Scratch.gdb\fc_FeatureToPoint',"C:\Program Files\ArcGIS\Desktop10.1\Metadata\Stylesheets\ArcGIS.xsl", r'X:\temp\Metadata.html')
  • Verwenden Sie einen HTML-Parser , um die Metadatendatei einzulesen und nach dem Verknüpfungsfeld aus dem Geoverarbeitungsverlauf des Verknüpfungsfeld-Tools zu suchen

  • Beispielausgabe des XSLT-Transformationstools

Ausgabe vom XSLT-Transformationstool

Nxaunxau
quelle
1
Das ist eine wirklich clevere Idee, von der ich dachte, dass sie wirklich vielversprechend ist, aber aus meinen Tests geht hervor, dass dies nur funktioniert, wenn die Datei mit dem GP-Tool "JoinField" verknüpft wurde, da dies als Teil des GP-Prozessverlaufs geschrieben wurde für diese Schicht. Wenn der Benutzer einen Join über die Benutzeroberfläche erstellt hat, ist die JoinField-Prozesszeile in der Ausgabedatei nicht vorhanden. Tolle Idee!
RyanKDalton
1
Ich würde mich sowieso nicht auf die GP-Geschichte verlassen. Wir versuchen, es so schnell wie möglich zu löschen, da es bei wiederkehrenden Prozessen schnell in eine große Datenmenge eingebunden wird, die eine Feature-Class nahezu unbrauchbar macht.
blah238
-1

Verknüpfte Tabellennamen befinden sich im IFeatureLayer - IFeatureLayerDefinition-Objekt als Zeichenfolge. Ich denke, sie enthält wahrscheinlich die Join-SQL und damit die Feldnamen.

http://edndoc.esri.com/arcobjects/8.3/diagrams/Map%20Layer%20Object%20Model.pdf

Oder meinst du, wenn du nicht auf dieses Objekt zugreifen kannst?

AnserGIS
quelle
IFeatureLayerDefinitionenthält nicht "Join SQL", sondern nur eine DefinitionExpressionEigenschaft, die die Definitionsabfrage des Feature-Layers verfügbar macht, sofern diese festgelegt ist. Hierbei handelt es sich um eine WHERE-Klausel, die die Anzeige der Zeilen einschränkt.
blah238
Es hat zwar eine RelationshipClassEigenschaft, aber ich denke, dies macht nur den letzten Join sichtbar. Sie müssten IRelQueryTablestattdessen verwenden, um sie alle zu erhalten.
blah238
-2

Um passende Felder unabhängig vom Feldnamen zu finden, können Sie Folgendes tun:

import arcpy

fc = r"temp/RiversJoined.shp"

fldList1 = [f.name for f in arcpy.ListFields(fc)]
fldList2 =[g.name for g in arcpy.ListFields(fc)]

for f in fldList1:
    values1 = [f_row[0] for f_row in arcpy.da.SearchCursor(fc, (f))]
    for g in fldList2:
        values2 = [g_row[0] for g_row in arcpy.da.SearchCursor(fc,(g))]
        #compare field values
        #get names of matching fields
        if (fldList2.index(g) != fldList1.index(f) and values1 == values2):
            print "match: " + str(g) + " match: "+ str(f)
mwil
quelle
Hey, an wen auch immer meine Antwort geklopft hat: Kannst du mir sagen, was mit meiner Antwort falsch ist? Vielen Dank.
mwil
1
Dies scheint die gestellte Frage nicht zu beantworten. Gleiches gilt für die Fuzzy-Vergleichsantwort. Felder, die identisch (oder sogar unscharf ähnlich) sind, haben keinen Einfluss darauf, ob sie tatsächlich in einem Join verwendet wurden oder nicht.
blah238