arcpy.da.UpdateCursor on joined tables?

10418
25
Jump to solution
05-01-2013 06:05 AM
ErikMartin
Occasional Contributor
Do data access update cursors work on joined tables?  This thread indicates that Search Cursors do, but I keep getting a "cannot update join table" error.  I have confirmed that I am trying to update the original table, not the joined table.  Here's the pertinent code:

arcpy.MakeFeatureLayer_management(FC, "FC_lyr") FC_lyr = "FC_lyr" arcpy.AddJoin_management(FC_lyr, "joinField", joinedFCTable, "joinField")  fields =("{}.DataField".format(FC_lyr), "{}.OtherDataFiedl".format(joinedFCTable)) where = '"{}.OBJECTID" IS NOT NULL'.format(joinedFCTable)  with arcpy.da.UpdateCursor(FC_lyr, fields, where) as rows:     for row in rows:         row[0] = row[0] + row[1] 


As an aside, I am trying to use the da.UpdateCursor because it is far faster than using field the calculator (code that I already have working) & I am trying to optimize speed.

Thanks,
-Erik
Tags (2)
0 Kudos
25 Replies
ErikMartin
Occasional Contributor
I'm having some trouble getting this to work.  I'm getting a "'dict' object is not callable error when I use the simple code below:


lutTbl = "New_Shapefile2"
targetTbl = "New_Shapefile"

lutDict = dict([(r[0], (r[1], r[2])) for r in arcpy.da.SearchCursor(lutTbl, ["ID","value","value2"])])
updateRows = arcpy.da.UpdateCursor(targetTbl, ["ID","value","value2"])
for updateRow in updateRows:
    joinFieldValue = updateRow[0]
    updateRow[1] = updateRow[1] + lutDict[joinFieldValue][0] #assuming these values are numeric and not strings or anything!
    updateRow[2] = updateRow[2] * lutDict[joinFieldValue][1] #assuming these values are numeric and not strings or anything!
    updateRows.updateRow(updateRow)
del updateRow, updateRows


I've tried lots of combinations of square brackets and paraentheses, but to no avail so far... is there some simple syntax i'm missing?

When I use my actual code (which has far more fields, so I'll spare the confusion) I'm actually getting a "can't concatenate 'str' and 'int' objects error.  This error does NOT have to do with my field type, but
0 Kudos
ChrisSnyder
Regular Contributor III
Hmmm.... I might have missed a bracket or something in my example.... Here's an "real" example that I know works:

slopeDict = dict([(r[0], (r[1], r[2], int(r[3] + .5))) for r in arcpy.da.SearchCursor(slopePctZoneStatTbl, ["VALUE","MIN","MAX","MEAN"])])

Another way to write this without so many confounded ([])()([[]]) symbols:

slopeDict = {}
searchRows = arcpy.da.SearchCursor(slopePctZoneStatTbl, ["VALUE","MIN","MAX","MEAN"])
for searchRow in searchRows:
    keyValue = searchRow[0]
    minValue = searchRow[1]
    maxValue = searchRow[2]
    meanValue = int(searchRow[3] + .5)
    slopeDict[keyValue] = (minValue, maxValue, meanValue)
del searchRow, searchRows


BTW: This assumes that your key values are all unique (I should have said that up front).

As for your concatenation issue, this illustration might help:

>>> print "hello" + 1
ERROR!
>>> print "hello" + str(1)
"hello1"
>>> print int("1") + float("1.1")
2.1
>>> print "hello" + "-" + str(1.1234)
hello-1.1234
0 Kudos
ErikMartin
Occasional Contributor
OK, thanks, I'll keep digging and will surely find the problem at some point.  Thanks for posting the alternate syntax -- it is definitely much easier to read.

Thanks again,
-Erik
0 Kudos
ErikMartin
Occasional Contributor
So I'm using this code in a couple places in my script.  I have it working successfully two of the times it is used, but two other times it is used, I keep getting an error.  I have been through the code character by character and there are no syntax errors -- what works in one place doesn't work in the other place.  The different instances of the code all use FCs that are derived from the same source FC -- a simple point layer (subsets are made from this source layer and I'm trying to "join" between these subsets)-- so all of the field types are identical between the occurrences where it is working and where it isn't working.  The only difference I can find between the occasions where it is working and where it isn't working is that where it is working there are the same number of records in the update and join tables (one record in each table).  Where it isn't working, the join table only has a few matches in the update table  (so this would be equivalent to joining and field calculating only on the selected records where ("joinTable.OBJECTID" is not null). 

The error I am given is  the "cannot concatenate 'str' and 'int' objects".  It is thrown whenever I try to access the join table dictionary with this line
updateRow[1] =  updateRow[1] + joinDict[joinFieldValue][0]


or, in fact, any time I try to use: joinDict[joinFieldValue][0]

so even this throws the same concatenation error:

arcpy.AddMessage(joinDict[joinFieldValue][0])


The joinFieldValue is successfully obtained from updateRow[0] and even if I hard code a joinvalue, like:

arcpy.AddMessage(joinDict[4220][0])


I get the same error

Do I need to add a conditional in somehow so that it only tries to access the dictionary if there is a match (is 'none' being returned and being treated as a string?)  Is there something else I am missing?  Again, I am confident there are no syntax errors and I am not trying to actually concatenate ints and strings. 

Thanks for the continued support!
-Erik
0 Kudos
MathewCoyle
Frequent Contributor
Not sure why you are getting that issue. It may be a case of nulls coming across as an empty string. You can get around this by simply adding int() around each argument when you make your calculations. You could alternatively use float() if there are decimal numbers.

updateRow[1] =  int(updateRow[1]) + int(joinDict[joinFieldValue][0])
0 Kudos
ErikMartin
Occasional Contributor
Thanks, Matthew, but no luck.  The problem occurs before I even try to make a calculation.  So even just this line throws the str/int error:

arcpy.AddMessage(joinDict[joinFieldValue][0])


Adding in int here didn't help (nor would I expect it to). 

arcpy.AddMessage(int(joinDict[joinFieldValue][0]))


Again, "joinFieldValue" is correctly populating with the join key (which happens to be an int).

I'll keep circling the problem... thanks for your help.
0 Kudos
MathewCoyle
Frequent Contributor
Can you print out a line of your dict showing the key and values?
0 Kudos
ErikMartin
Occasional Contributor
Here's a line of it:

{4931: (1466.31859047, 0.7298187853203999, 0.181307540288, 0.0, 0.0, 0.0, 0.0, 0.0, 1.45650000000222, 280800.0, 266454.070051103, 0, 3, 2524.95936472164, 312.0, 1303.0, 214200.0, 72900.0, 0)}
0 Kudos
ErikMartin
Occasional Contributor
Here's a line of it:

{4931: (1466.31859047, 0.7298187853203999, 0.181307540288, 0.0, 0.0, 0.0, 0.0, 0.0, 1.45650000000222, 280800.0, 266454.070051103, 0, 3, 2524.95936472164, 312.0, 1303.0, 214200.0, 72900.0, 0)}



Note that there is only ever 1 key/value pair in the "join" dictionary at a time.  In one case where I'm having problems, there is only one record (of many) that it will join to in the "update" table.  I still cannot get this working.  Later, there is another instance where there are potentially >1 records that the single "join" key would join to.  Will cross that bridge when I get to it...
0 Kudos
MathewCoyle
Frequent Contributor
You could try str() for your print messages though that shouldn't be an issue. Do you get this for any record in your dict or does it only pop up after a while?
0 Kudos