Identificazione programmatica del campo unito in ArcMap?


9

È possibile identificare a livello di codice il campo Join utilizzato per unire insieme due set di dati in ArcMap? Attualmente sto usando ArcGIS 10.0, SP5 e preferirei una soluzione ArcPy , tuttavia non sarei contrario alle altre soluzioni, se una soluzione ArcPy non fosse disponibile.

Un metodo che ho provato è stato quello di passare in rassegna tutti i campi e cercare un "baseName" corrispondente, ma questa è solo una "ipotesi istruita" in cui si spera che i nomi dei campi in entrambi i database siano gli stessi.

Per una rappresentazione grafica di ciò che sto cercando, fondamentalmente voglio identificare "Input Join Field" e "Output Join Field" come si vede nella finestra di dialogo "Aggiungi Join", ma dopo tutto, ovviamente.

Come identificare "Input Join Field" e "Output Join Field"?

Questa è una domanda tag-on a: Un "Join" può essere rilevato a livello di codice? , ma in questo caso desidero estendere la funzionalità per identificare i CAMPI utilizzati per unire i due (o più) set di dati.


Con quale versione di ArcGIS stai lavorando? E presumo in base ai tag che stai cercando specificamente un modo per farlo con arcpy e non ArcObjects?
blah238,

Attualmente sto usando ArcGIS 10.0, SP5. E sì, sto cercando / sperando in una soluzione ArcPy, tuttavia non sarei contrario a una soluzione ArcObjects, se questa è l'unica alternativa.
RyanKDalton,

1
Ecco alcuni documenti forse rivelatori : edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/… Coinvolge pRelClass Questa è la RelationshipClass utilizzata per definire le tabelle di join e i campi di join nonché la cardinalità. Il metodo Open crea una nuova RelQueryTable o restituisce un riferimento a una RelQueryTable esistente se quella classe è già stata creata. Potresti invocare questo metodo e trovare il riferimento che coinvolge thepRelClass
lewis

@lewis, non è necessario utilizzare l'oggetto factory per ottenere un riferimento a una RelQueryTable esistente - vedere la mia risposta.
blah238

Risposte:


7

Ecco un approccio ArcObjects, basato su questo esempio , per enumerare tutti i join su un livello ed elencare i nomi delle tabelle di destinazione e di origine e le chiavi primarie ed esterne:

  1. Ottieni un riferimento a uno ILayerche ha uno o più join
  2. Lancia il ILayertoIDisplayTable
  3. Trasmetti la IDisplayTable.DisplayTableproprietà aIRelQueryTable
  4. Mentre la tabella corrente è una IRelQueryTable:
    1. Ispezionare le RelQueryTable's DestinationTablee SourceTableproprietà
    2. Ispeziona le proprietà OriginPrimaryKeye OriginForeignKeydella IRelQueryTable.RelationshipClassproprietà.
    3. Impostare la tabella corrente RelQueryTablesulla SourceTableproprietà corrente

Questo script Python (utilizzando i comtype e questo modulo helper ) esaminerà tutti i join, dal più recente al meno recente, e stamperà i nomi delle tabelle di destinazione e di origine, la chiave primaria di origine e la chiave esterna di origine per ciascun 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)

Esempio di output, dato un livello sorgente con tre join:

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

Per altre info, vedi Come posso accedere ad ArcObjects da Python?


Sembra molto promettente. Ho installato il pacchetto comtypes e aggiunto il codice della funzione helper, ma ottengo l'errore "global name 'esriGeoDatabase' is not defined". Dove / come dovrebbe essere definito nel codice che precede la riga while CType(table, esriGeoDatabase.IRelQueryTable)?
RyanKDalton,

Non l'ho incluso, ma a un certo punto devi importare i wrapper di comtypes attorno alle librerie di oggetti ESRI specifiche di cui hai bisogno. Utilizzando il mio modulo di aiuto è semplice come esriGeoDatabase = GetESRIModule("esriGeoDatabase").
blah238

Capito grazie. Funzionerà anche per i livelli in ArcMap? Sto passando ogni livello layerList = arcpy.mapping.ListLayers(mxd)nel listJoins(table)codice, ma salta la whilefrase.
RyanKDalton,

Non penso che tu possa eseguire il cast tra oggetti arcpici e oggetti di tipo comtype, quindi devi ottenere il riferimento ILayer tramite ArcObjects. Ho aggiornato il codice per includere un esempio più completo. Questo dovrebbe essere in grado di essere utilizzato sia dentro che fuori processo commentando / decommentando le righe pertinenti.
blah238,

Avvicinandoti, grazie per la pazienza di passaggio ... ora, come hai inviato il file del documento della mappa attuale (* .mxd) che vuoi guardare? app.Documentritorna con'NoneType' object has no attribute 'Document'
RyanKDalton

1

Metti tutti i dati dei campi in stringhe, (dopo averli ordinati) confrontali con una funzione fuzzycompare e seleziona quelli che hanno dato la migliore corrispondenza o corrispondenza oltre una certa precisione.

Questa soluzione è quando alcuni dati non si adattano. Se pensi che entrambe le colonne vadano sempre bene, ordina e confronta per una corrispondenza perfetta con una normale funzione di confronto.


0

Prova questo:

  • Utilizzare lo strumento di trasformazione XSLT dal set di strumenti Metadata per scrivere un file di metadati xml / html per il set di dati in questione.

    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')
  • Utilizzare un parser HTML per leggere il file dei metadati e cercare il campo di join dalla cronologia di geoprocessing dello strumento Campo di join

  • Output di esempio dallo strumento di trasformazione XSLT

Output dallo strumento di trasformazione XSLT


1
È un'idea davvero intelligente che pensavo fosse davvero promettente, ma dai miei test sembra che funzionerà solo se il file è stato unito usando lo strumento GP chiamato "JoinField", poiché questo è scritto come parte della cronologia dei processi GP per quello strato. Se l'utente ha creato un join tramite l'interfaccia utente, la riga del processo JoinField non esiste nel file di output. Ottima idea però!
RyanKDalton,

1
Per questo non farei affidamento sulla cronologia dei GP. Cerchiamo di eliminarlo il prima possibile perché per i processi ricorrenti si monta rapidamente in un'enorme quantità di dati che rendono quasi inutilizzabile una classe di caratteristiche.
blah238

-1

I nomi delle tabelle unite si trovano nell'oggetto IFeatureLayer - IFeatureLayerDefinition come una stringa .. che penso probabilmente contenga il join SQL e quindi i nomi dei campi.

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

O vuoi dire se non riesci ad accedere a quell'oggetto?


IFeatureLayerDefinitionnon contiene "join SQL", ha solo una DefinitionExpressionproprietà che espone la query di definizione del feature layer, se impostata, che è una clausola WHERE che limita le righe visualizzate.
blah238

Ha una RelationshipClassproprietà, tuttavia, ma penso che questo esponga solo il join più recente. Dovresti usare IRelQueryTableinvece per ottenerli tutti.
blah238

-2

per trovare i campi corrispondenti indipendentemente dal nome del campo, potresti fare qualcosa del genere:

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)

ehi a chiunque abbia bussato alla mia risposta: puoi dirmi cosa c'è che non va nella mia risposta? Grazie.
mwil,

1
Questo non sembra rispondere alla domanda come richiesto. Lo stesso con la risposta comparativa fuzzy. I campi identici (o anche sfocati) non influiscono sul fatto che siano stati effettivamente utilizzati o meno in un join.
blah238
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.