¿Programar la identificación del campo unido en ArcMap?

9

¿Es posible identificar mediante programación el campo de unión que se está utilizando para unir dos conjuntos de datos en ArcMap? Actualmente estoy usando ArcGIS 10.0, SP5 y preferiría una solución ArcPy , sin embargo, no me opondría a otras soluciones, si una solución ArcPy no está disponible.

Un método que probé fue recorrer todos los campos y buscar un "baseName" coincidente, pero eso es solo una "suposición educada" en la que esperas que los nombres de campo en ambas bases de datos sean los mismos.

Para una representación gráfica de lo que busco, básicamente quiero identificar el "Campo de unión de entrada" y el "Campo de unión de salida" como se ve en el cuadro de diálogo "Agregar unión", pero después del hecho, por supuesto.

¿Cómo identificar el "Campo de unión de entrada" y el "Campo de unión de salida"?

Esta es una pregunta etiquetada para ¿Se puede detectar un "Join" mediante programación? , pero en este caso quiero ampliar la funcionalidad para identificar los CAMPOS que se utilizan para unir los dos (o más) conjuntos de datos.

RyanKDalton
fuente
¿Con qué versión de ArcGIS está trabajando? Y supongo que, en base a las etiquetas, ¿está buscando específicamente una forma de hacer esto con arcpy y no con ArcObjects?
blah238
Actualmente estoy usando ArcGIS 10.0, SP5. Y sí, estoy buscando / esperando una solución ArcPy, sin embargo, no me opondría a una solución ArcObjects, si esa es la única alternativa.
RyanKDalton
1
Aquí hay alguna documentación posiblemente reveladora : edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/… Implica la clase pRelClass Esta es la relación de clase utilizada para definir las tablas de unión y los campos de unión, así como la cardinalidad. El método Open crea una nueva RelQueryTable o devuelve una referencia a una RelQueryTable existente si esa clase ya se ha creado. Puede invocar este método y encontrar la referencia que involucra thepRelClass
lewis
@lewis, no necesita usar el objeto de fábrica para obtener una referencia a una RelQueryTable existente; consulte mi respuesta.
blah238

Respuestas:

7

Aquí hay un enfoque de ArcObjects, basado en este ejemplo , para enumerar todas las uniones en una capa y enumerar sus nombres de tabla de origen y destino y las claves primarias y externas:

  1. Obtenga una referencia a una ILayerque tenga una o más uniones
  2. Lanzar el ILayeraIDisplayTable
  3. Emitir la IDisplayTable.DisplayTablepropiedad aIRelQueryTable
  4. Mientras que la tabla actual es un IRelQueryTable:
    1. Inspeccionar los RelQueryTable's DestinationTabley SourceTablepropiedades
    2. Inspeccionar las propiedades OriginPrimaryKeyy OriginForeignKeyde la IRelQueryTable.RelationshipClasspropiedad.
    3. Establecer la tabla actual de la corriente RelQueryTable's SourceTablepropiedad

Este script de Python (usando comtypes y este módulo auxiliar ) pasará por todas las uniones, de la más reciente a la más temprana, e imprimirá los nombres de la tabla de origen y destino, la clave primaria de origen y la clave externa de origen para cada combinación:

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)

Ejemplo de salida, dada una capa fuente con tres combinaciones:

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

Para obtener más información, consulte ¿Cómo accedo a ArcObjects desde Python?

blah238
fuente
Esto se ve muy prometedor. Tengo el paquete comtypes instalado y el código de función auxiliar agregado, pero recibo el error "global name 'esriGeoDatabase' is not defined". ¿Dónde / cómo debería definirse en el código que precede a la línea while CType(table, esriGeoDatabase.IRelQueryTable)?
RyanKDalton
No lo incluí, pero en algún momento tienes que importar los envoltorios de tipos alrededor de las bibliotecas de objetos ESRI específicas que necesitas. Usar mi módulo de ayuda es tan simple como esriGeoDatabase = GetESRIModule("esriGeoDatabase").
blah238
Gracias. ¿Funcionará esto también para capas en ArcMap? Estoy pasando cada capa desde layerList = arcpy.mapping.ListLayers(mxd)el listJoins(table)código, pero se omite en la whiledeclaración.
RyanKDalton
No creo que pueda lanzar entre objetos arcpy y comtypes, por lo que debe obtener la referencia ILayer a través de ArcObjects. He actualizado el código para incluir un ejemplo más completo. Esto debería poder usarse tanto dentro como fuera del proceso comentando / descomentando las líneas relevantes.
blah238
Acercándonos, gracias por la paciencia del recorrido ... ahora, ¿cómo enviaste el archivo de documento de mapa real (* .mxd) que quieres ver? app.Documentregresa con'NoneType' object has no attribute 'Document'
RyanKDalton
1

Ponga todos los datos de los campos en cadenas (después de haberlos ordenado) compárelos con una función de comparación difusa y seleccione aquellos que dieron la mejor coincidencia o coincidencia con cierta precisión.

Esta solución es cuando algunos datos no encajan. Si cree que ambas columnas siempre encajarían, simplemente ordene y compare para una combinación perfecta con una función de comparación ordinaria.

Debajo del radar
fuente
0

Prueba esto:

  • Utilice la herramienta de transformación XSLT del conjunto de herramientas de metadatos para escribir un archivo de metadatos xml / html para el conjunto de datos en cuestión.

    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')
  • Use un analizador HTML para leer el archivo de metadatos y busque el campo de unión desde el historial de geoprocesamiento de la herramienta Campo de unión

  • Salida de muestra de la herramienta de transformación XSLT

Salida de la herramienta de transformación XSLT

Nxaunxau
fuente
1
Esa es una idea realmente inteligente que pensé que era muy prometedora, pero según mis pruebas, parece que esto solo funcionará si el archivo se unió usando la herramienta GP llamada "JoinField", ya que esto está escrito como parte del historial del proceso GP para esa capa Si el usuario ha creado una unión a través de la interfaz de usuario, la línea de proceso JoinField no existe en el archivo de salida. ¡Gran idea sin embargo!
RyanKDalton
1
No confiaría en la historia de GP para esto de todos modos. Intentamos eliminarlo lo antes posible porque para procesos recurrentes se acumula rápidamente en una gran cantidad de datos que hace que una clase de entidad sea casi inutilizable.
blah238
-1

Los nombres de las tablas unidas están en el objeto IFeatureLayer - IFeatureLayerDefinition como una cadena ... que creo que probablemente contiene el SQL de unión y, por lo tanto, los nombres de campo.

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

¿O quieres decir si no puedes acceder a ese objeto?

AnserGIS
fuente
IFeatureLayerDefinitionno contiene el "join SQL", solo tiene una DefinitionExpressionpropiedad que expone la consulta de definición de la capa de entidades, si está establecida, que es una cláusula WHERE que limita las filas que se muestran.
blah238
Sin embargo, tiene una RelationshipClasspropiedad, pero creo que esto solo expone la unión más reciente. Debería usar IRelQueryTableen su lugar para obtenerlos todos.
blah238
-2

para encontrar campos coincidentes independientemente del nombre del campo, puede hacer algo como esto:

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
fuente
oye a quien llamó mi respuesta: ¿puedes decirme qué hay de malo en mi respuesta? Gracias.
mwil
1
Esto no parece responder la pregunta como se le preguntó. Lo mismo con la respuesta de comparación difusa. Los campos que son idénticos (o incluso similares) no influyen en si realmente se han utilizado o no en una unión.
blah238