Replace/Update Geometry and some attributes but keep some existing attributes?

1393
3
Jump to solution
04-13-2021 07:45 AM
AlexP_
by
Occasional Contributor III

Hello,

I have ArcGIS Pro 2.7.2 and sde, sql server. Have two feature classes. One feature class is update weekly from the county and one feature class is local city. It needs to be import to the city from the county. 

How can replace/update geometry and some fields attribute but also need to keep some existing attribute fields?

For example, existing parcel geometry is update (shape has been changed) from the county and need to replace/update existing geometry from the city. keep existing info some fields such as parcel number but also some fields attribute need to be update such as owner, tax.  Is there a way to do it in script, tool or other methods? Need to do this weekly. Please assist. Thank you

Alex

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

Then it gets more complex...

county_fields = ["Folio", "Address", "SHAPE@", "Tax", "Owner"]
city_fields = ["folio", "address", "SHAPE@", "tax_rate", "parcel_owner"]

# read the rows of the county_fc
# [ [values_1], [values_2], ... ]
county_rows = [cr for cr in arcpy.da.SearchCursor(county_fc, county_fields)]

# create a lookup dictionary, using folio and address as key
# { [folio_1, address_1]: [values_1], [folio_2, address_2]: [values_2], ... }
county_dict = {cr[0:1]: cr for cr in county_rows}

# loop through the city_fc, lookup the county parcel values and update
with arcpy.da.UpdateCursor(city_fc, city_fields) as city_parcels:
    for row in city_parcels:
        key = row[0:1]
        try:
            new_row = county_dict[key]
            # Only update if something changed
            # I can't test this right now, it could be that this doesn't 
            # work for SHAPE@
            if new_row != row:
                # print a message telling you what changed
                print("parcel with folio and address = {} was edited. Old values: {}. New Values: {}".format(key, row, new_row))
                city_parcels.updateRow(new_row)
            # remove row from county_rows
            county_rows.remove(new_row)
        except KeyError:
            print("county_fc has no parcel with folio and address = {}".format(key))
            missing_parcels.append(key)

# We removed the entries in county_rows that were already in city_fc.
# All entries still in county_rows must be new entries in county_fc.
print("There are {} new entries in county_fc.".format(len(county_rows ))
for new_entry in county_rows :
    print(new_entry)

if len(county_dict) > 0:
    # Copy the new county parcels to city_fc
    with arcpy.da.InsertCursor(city_fc, city_fields) as city_parcels:
        for new_entry in county_rows:
            city_parcels.insertRow(new_entry)
    

Have a great day!
Johannes

View solution in original post

3 Replies
JohannesLindner
MVP Frequent Contributor

The basic code would be something like this:

county_fc = "path/to/county/featureclass"
city_fc = "path/to/city/featureclass"

# define the fields that have to be updated
# all other fields will stay the same
# same order for both feature classes
# you need a field that has the same values in both feature classes,
# e.g. ParcelID. In this example, that field has to be the first element
# of the field lists.
county_fields = ["ParcelID", "SHAPE@", "Tax", "Owner"]
city_fields = ["parcel_id", "SHAPE@", "tax_rate", "parcel_owner"]

# read the rows of the county_fc
# [ [values_1], [values_2], ... ]
county_rows = [cr for cr in arcpy.da.SearchCursor(county_fc, county_fields)]

# create a lookup dictionary, using the parcel id as key
# remember, in this example, it's the first element of county_fields
# { parcel_id_1: [values_1], parcel_id_2: [values_2], ... }
county_dict = {cr[0]: cr for cr in county_rows}

# loop through the city_fc, lookup the county parcel values and update
with arcpy.da.UpdateCursor(city_fc, city_fields) as city_parcels:
    for row in city_parcels:
        parcel_id = row[0]
        try:
            new_row = county_dict[parcel_id ]
            city_parcels.updateRow(new_row)
        except KeyError:
            print("county_fc has no parcel with parcel_id = {}".format(parcel_id))

You can save that as a standalone Python script and run that manually, or you can schedule it to run periodically, or you can use the code in a script tool.


Have a great day!
Johannes
AlexP_
by
Occasional Contributor III

@JohannesLindner Thank you for the script. I realized I didn't explain the whole thing. Need to keep existing parcel number from the city and to avoid the new parcel number information from the county to replace. Because sometimes they change the new parcel number with update geometry. but don;t want to have new parcel number. still need to update/replace geometry and some attribute fields.

like have two fields folio and address same values from both feature classes and use it as look up directory key .

what about new data come in that is not exist yet?  will it work input data to the city from the county if it is not exist? what would happen if the address change with existing folio? How would i know what changed? Is there alert? Please kindly clarify.

0 Kudos
JohannesLindner
MVP Frequent Contributor

Then it gets more complex...

county_fields = ["Folio", "Address", "SHAPE@", "Tax", "Owner"]
city_fields = ["folio", "address", "SHAPE@", "tax_rate", "parcel_owner"]

# read the rows of the county_fc
# [ [values_1], [values_2], ... ]
county_rows = [cr for cr in arcpy.da.SearchCursor(county_fc, county_fields)]

# create a lookup dictionary, using folio and address as key
# { [folio_1, address_1]: [values_1], [folio_2, address_2]: [values_2], ... }
county_dict = {cr[0:1]: cr for cr in county_rows}

# loop through the city_fc, lookup the county parcel values and update
with arcpy.da.UpdateCursor(city_fc, city_fields) as city_parcels:
    for row in city_parcels:
        key = row[0:1]
        try:
            new_row = county_dict[key]
            # Only update if something changed
            # I can't test this right now, it could be that this doesn't 
            # work for SHAPE@
            if new_row != row:
                # print a message telling you what changed
                print("parcel with folio and address = {} was edited. Old values: {}. New Values: {}".format(key, row, new_row))
                city_parcels.updateRow(new_row)
            # remove row from county_rows
            county_rows.remove(new_row)
        except KeyError:
            print("county_fc has no parcel with folio and address = {}".format(key))
            missing_parcels.append(key)

# We removed the entries in county_rows that were already in city_fc.
# All entries still in county_rows must be new entries in county_fc.
print("There are {} new entries in county_fc.".format(len(county_rows ))
for new_entry in county_rows :
    print(new_entry)

if len(county_dict) > 0:
    # Copy the new county parcels to city_fc
    with arcpy.da.InsertCursor(city_fc, city_fields) as city_parcels:
        for new_entry in county_rows:
            city_parcels.insertRow(new_entry)
    

Have a great day!
Johannes