Yardi Voyager ships with 9,793 standard tables. Nobody who works in it learned that number from documentation, because there mostly isn't any at the table level — no field guide, no ERD, no searchable reference that tells you which of those tables actually holds tenant status or charge history. What experienced Yardi people have instead is a reasoning process, built up over years of guessing wrong and remembering why.
Here's that process, made explicit.
Start with the entity, not a guessed name
The instinct is to guess a table name that sounds right — LEASE, TENANTS, CHARGES — and grep for it. That fails constantly, because Voyager's naming doesn't follow a single obvious pattern across modules. The better first move is to name the entity type you're after (a tenant, a charge, a GL posting, a work order) and let the naming grammar narrow the search from there, instead of guessing a whole word.
The prefix grammar is your first real filter
Voyager columns follow a consistent Hungarian-notation grammar: h marks a handle or foreign key (hMy is almost always the primary key, hProp a foreign key to PROPERTY), s marks a string, i an integer or enum discriminator, d a decimal amount, dt a datetime, b a boolean stored as a numeric flag, and u a Unicode string (uCode, uName). tRowVersion is a SQL Server rowversion — a timestamp only in name, never usable as a real date.
Once you know that grammar, a table's own column list starts explaining itself instead of hiding behind cryptic names.
The wrong turn almost everyone takes once: person subtypes
If you're looking for the tenant table, TENANT is right — but its primary key is HMYPERSON, not HMY. TENANT, VENDOR, ROOM, and Customer are all subtypes of a PERSON supertype, and they share that supertype's key column instead of getting their own. Join on TENANT.HMY and the query fails outright, because the column doesn't exist. Foreign keys that reference these tables — hTenant, hVendor — point at HMYPERSON, not HMY. PROSPECT and PERSON itself are the exception and do use plain hMy.
It's a small distinction, but it's the single most common reason a first-try join against tenant or vendor data fails for people new to the schema.
When "the table" is actually a row in another table
Some of the most-needed data doesn't live in its own table at all. Columns named hRecord (appearing on roughly 207 tables) and hCode (376 tables) are polymorphic references — the table they point to isn't fixed, it's determined by a companion iObjectType or iType column sitting in the same row. Join hRecord straight to a guessed target table without filtering that discriminator column first, and you'll silently pull rows for the wrong entity type. Voyager keeps a Role table (iObjectType/sObjectType) that enumerates the valid object types — checking it before writing the join is the difference between a correct query and a plausible-looking wrong one.
There's a second layer of this same trap in the naming itself: many modules reference PROPERTY through a column called hProp, but roughly three times as many use hProperty instead — an older-versus-newer convention split across the schema. Same target table, two different column names depending on which corner of Voyager you're in.
Views, custom fields, and generated clutter
Not everything that looks like a table is one. Real Voyager installs accumulate custom views layered over base tables, and a schema browser often doesn't distinguish them clearly. Two patterns are worth knowing on sight: tables containing BUT_ (PROPBUT_AMENITY, LEASEBUT_RSR) are Yardi's per-entity custom-field framework — consultant-built, client-specific, and never safe to assume exist on a different install. Views named PV_<number> are auto-generated per saved property list, not hand-written logic — they're data artifacts, not schema design.
And a quiet trap that catches people who assume every table is fair game for a join: audit columns like hUserCreatedBy and hUserModifiedBy appear on more than 2,000 tables and all point back to the same user table. They answer "who touched this record," never "what business entity relates to this one" — treating them as a real relationship produces a technically-valid join that means nothing.
Even with all of that in hand, the honest failure mode is relying on a table you've only partially catalogued. A table where only a couple of its dozen-plus columns are documented can still tempt you into writing a query against it — and that's exactly the kind of partial-knowledge mistake that produces a confidently wrong answer instead of an error. The safer habit is checking a table's full column list before trusting any query built against it, not just the columns that happen to be familiar.
What this looks like with the guessing removed
None of this is exotic — it's the accumulated tribal knowledge that makes an experienced Voyager consultant faster than a new one at the exact same task: finding the table that actually holds what they need. The problem is that knowledge normally lives in one person's head, gets relearned the hard way by everyone else, and doesn't show up in any onboarding document.
That's the gap PropETL's SQL Assistant closes. It carries a queryable knowledge base of the full standard Voyager schema — 9,793 tables, 137,000+ columns with their types and key roles — plus the curated conventions above already built in: the naming grammar, the person-subtype trap, polymorphic hRecord/hCode handling, and which relationships are real business joins versus audit noise. Ask it in plain English which tables hold what you need, and it answers with the actual tables and columns instead of a guess.
Schema search is included in every PropETL tier. Start the free 7-day trial — no credit card — and ask it the table question you've been meaning to look up.
