Identificando programaticamente campo unido no ArcMap?

9

É possível identificar programaticamente o campo Join que está sendo usado para unir dois conjuntos de dados juntos no ArcMap? Atualmente, estou usando o ArcGIS 10.0, SP5 e preferiria uma solução ArcPy , no entanto, não me oporia a outras soluções, se uma solução ArcPy não estiver disponível.

Um método que tentei foi percorrer todos os campos e procurar um "baseName" correspondente, mas esse é apenas um "palpite", no qual você espera que os nomes de campo nos dois bancos de dados sejam os mesmos.

Para uma representação gráfica do que estou procurando, basicamente quero identificar o "Campo de junção de entrada" e "Campo de junção de saída", como visto na caixa de diálogo "Adicionar junção", mas depois do fato, é claro.

Como identificar o "Campo de junção de entrada" e "Campo de junção de saída"?

Esta é uma pergunta de tag para "Uma junção" pode ser detectada programaticamente? , mas neste caso, desejo estender a funcionalidade para identificar os FIELDs que estão sendo usados ​​para unir os dois (ou mais) conjuntos de dados.

RyanKDalton
fonte
Com qual versão do ArcGIS você está trabalhando? E suponho que, com base nas tags que você procura especificamente, seja uma maneira de fazer isso com o Arcpy e não com o ArcObjects?
blah238
Atualmente, estou usando o ArcGIS 10.0, SP5. E sim, estou procurando / esperando por uma solução ArcPy, mas não me oponho a uma solução ArcObjects, se essa for a única alternativa.
RyanKDalton
11
Aqui está uma documentação possivelmente reveladora : edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/… Envolve o pRelClass Esta é a RelationshipClass usada para definir as tabelas de junção e os campos de junção, bem como a cardinalidade. O método Open cria uma nova RelQueryTable ou retorna uma referência a uma RelQueryTable existente se essa classe já tiver sido criada. Você pode invocar esse método e encontrar a referência que envolve thepRelClass
lewis
@lewis, você não precisa usar o objeto factory para obter uma referência a uma RelQueryTable existente - veja minha resposta.
blah238

Respostas:

7

Aqui está uma abordagem do ArcObjects, baseada neste exemplo , para enumerar todas as junções em uma camada e listar seus nomes de tabela de destino e origem e chaves primárias e estrangeiras:

  1. Obter uma referência a uma ILayerque tenha uma ou mais junções
  2. Transmitir ILayerparaIDisplayTable
  3. Transmitir a IDisplayTable.DisplayTablepropriedade paraIRelQueryTable
  4. Enquanto a tabela atual é uma IRelQueryTable:
    1. Inspeccionar os RelQueryTable's DestinationTablee SourceTablepropriedades
    2. Inspecione as propriedades OriginPrimaryKeye OriginForeignKeyda IRelQueryTable.RelationshipClasspropriedade.
    3. Defina a tabela atual para o atual RelQueryTable's SourceTablepropriedade

Esse script Python (usando comtypes e este módulo auxiliar ) percorrerá todas as junções, do mais recente ao mais antigo, e imprimirá os nomes das tabelas de destino e de origem, chave primária de origem e chave estrangeira de origem para cada associação:

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)

Exemplo de saída, dada uma camada de origem com três junções:

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 mais informações, consulte Como acesso o ArcObjects a partir do Python?

blah238
fonte
Isso parece muito promissor. Eu tenho o pacote comtypes instalado e o código da função auxiliar adicionado, mas recebo o erro "global name 'esriGeoDatabase' is not defined". Onde / como deve ser definido no código que precede a linha while CType(table, esriGeoDatabase.IRelQueryTable)?
precisa saber é o seguinte
Não o incluí, mas em algum momento você precisa importar os invólucros comtypes em torno das bibliotecas de objetos ESRI específicas necessárias. Usando meu módulo auxiliar é tão simples quanto esriGeoDatabase = GetESRIModule("esriGeoDatabase").
precisa saber é o seguinte
Entendi, obrigado. Isso também funcionará para camadas no ArcMap? Eu estou passando cada camada de layerList = arcpy.mapping.ListLayers(mxd)dentro do listJoins(table)código, mas ele pula fora no whilecomunicado.
precisa saber é o seguinte
Eu não acho que você possa converter entre objetos arcpy e objetos comtypes, portanto, você precisa obter a referência do ILayer através do ArcObjects. Atualizei o código para incluir um exemplo mais completo. Isso deve poder ser usado dentro e fora do processo, comentando / descomentando as linhas relevantes.
precisa saber é o seguinte
Aproximando-se, obrigado pela paciência ... agora, como você enviou o arquivo de documento de mapa real (* .mxd) que deseja examinar? app.Documentvolta com'NoneType' object has no attribute 'Document'
RyanKDalton
1

Coloque todos os dados dos campos em seqüências de caracteres (depois de ordená-los) compare-os com uma função de comparação difusa e selecione aqueles que deram a melhor correspondência ou correspondência além de uma certa precisão.

Essa solução é quando alguns dados não cabem. Se você acha que as duas colunas sempre se encaixam, basta pedir e comparar para uma combinação perfeita com uma função de comparação comum.

Abaixo do radar
fonte
0

Tente o seguinte:

  • Use a ferramenta Transformação XSLT do conjunto de ferramentas Metadados para gravar um arquivo de metadados xml / html para o conjunto de dados em questão.

    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 um analisador de HTML para ler o arquivo de metadados e procurar o campo de junção no histórico de geoprocessamento da ferramenta Join Field

  • Saída de amostra da ferramenta Transformação XSLT

Saída da ferramenta Transformação XSLT

Nxaunxau
fonte
11
Essa é uma ideia realmente inteligente que eu pensei que tinha uma promessa real, mas pelos meus testes, parece que isso só funcionará se o arquivo tiver sido juntado usando a GP Tool chamada "JoinField", pois isso está escrito como parte do histórico do processo da GP para essa camada. Se o usuário criou uma associação por meio da interface do usuário, a linha de processo JoinField não existe no arquivo de saída. Ótima idéia!
RyanKDalton
11
De qualquer forma, eu não confiaria na história do GP. Tentamos excluí-lo o mais rápido possível porque, para processos recorrentes, ele monta rapidamente em uma enorme quantidade de dados que torna uma classe de recurso quase inutilizável.
blah238
-1

Os nomes das tabelas unidas estão no objeto IFeatureLayer - IFeatureLayerDefinition como uma seqüência de caracteres .. que eu acho que provavelmente contém a junção SQL e, portanto, os nomes dos campos.

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

Ou você quer dizer se você não pode acessar esse objeto?

AnserGIS
fonte
IFeatureLayerDefinitionnão contém o "join SQL", ele possui apenas uma DefinitionExpressionpropriedade que expõe a consulta de definição da camada de recurso, se definida, que é uma cláusula WHERE que limita quais linhas são exibidas.
315:
No RelationshipClassentanto, ele possui uma propriedade, mas acho que isso apenas expõe a associação mais recente. Você precisaria usar IRelQueryTablepara obtê-los todos.
blah238
-2

para encontrar campos correspondentes, independentemente do nome do campo, você pode fazer algo assim:

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
fonte
ei para quem bateu na minha resposta: você pode me dizer o que há de errado com a minha resposta? obrigado.
31713 mhil
11
Isso não parece responder à pergunta conforme solicitado. O mesmo com a resposta de comparação difusa. Os campos que são idênticos (ou mesmo parecidos) não têm importância se eles realmente foram usados ​​em uma junção.
blah238