idfg-bthomas's blog

ArcGIS One-To-Many Labeling

ArcGIS is just plain lousy at dealing with any relationship that isn't one-to-one.

We all have a slew of hacks just to deal with this limitation. I for one regularly am creating temporary cross-tab queries so I can represent multiple sample results at a collection point, fish surveyed at a cross-section and a host of other relationships.

The classic example for mapping comes from the cadastral community and condominium lots. It's an odd situation where more than one person has title to the same piece of ground. How do you represent this?

I've got a new trick thanks to Mohammed Hoque's article in ArcUser Magazine.

We're going to do a database query inside a label expression, loop through the results and output the entire list to label.

For our example we'll use Outfitting Areas in Idaho and we'll label them with the Outfitters and Guide License Numbers and Outfitter Names.

1.) Open ArcGIS and add your spatial layer with the unique identifier shared with your database.
2.) In the label expression, click Advanced

3.) Replace the labeling expression with the following:

Function FindLabel ([ID])
Dim strQry, strInfo, i
i = 1
strQry = "SELECT Outfitter FROM VU_GIS_Labeling WHERE ID = " & [ID]
Dim Conn
set Conn = createobject("ADODB.Connection")
Dim rs
set rs = createObject("ADODB.Recordset")
Conn.Open "PROVIDER=SQLOLEDB;Integrated Security=SSPI; Persist Security Info=False; Initial Catalog=aDatabaseName; Data Source=aServerName"
Conn.CursorLocation = 3
rs.Open strQry, Conn, 3, 1, 1
'if more than one records are found, append to the existing string.
Select Case rs.RecordCount
Case -1, 0
'If no record is found, return empty string
strInfo = ""
Case 1
'reading only the first record
strInfo = rs.Fields("Outfitter")
Case Else
Do While Not rs.eof
'if multiple records indicate how many using count
strInfo = strInfo & vbNewLine & rs.Fields("Outfitter") & " (" & i & ")"
i = i + 1

End Select
'closing connections this is a must
Set rs = Nothing
Set Conn = Nothing

'returning string for labeling
FindLabel = strInfo
End Function

You'll need to replace the bold values with those appropriate for your situation.

This example also uses SQL Server, different databases require different database connection strings:

“PROVIDER=OraOLEDB.Oracle; Data Source=aDatabaseName; User ID=aUserName; Password=aPassword”

“driver={MySQL ODBC 3.51 Driver}; Server=aServerName; Database=aDatabaseName; uid=aUserName; PWD=aPassword”

Microsoft Access
“PROVIDER=Microsoft.Jet.OLEDB.4.0; Data Source=c:\myDatabase.mdb;”

Microsoft SQL Server (using Windows NT Integrated security)
“Provider=SQLOLEDB; Integrated Security=SSPI; Persist Security Info=False; Initial Catalog=aDatabaseName; DataSource=aServerName”

4.) Finally, test your label expression for typos using the Verify button and if successful, OK your way out.

The final product: