Skip to main content
RevenueBase data is organized into separate tables that link together through shared keys. This page explains how the tables relate and how to join them correctly.

Entity relationship overview

Here’s how the main tables connect:
organizations (1) ──── (many) people/contacts
    │                        │
    │                        │
    └──── (1) insights ──────┘
    
people ──── (1) historical_experience (via linkedin_url)
Key relationships:
  • People join to Organizations via RBID_ORG = RBID (many-to-one)
  • Insights join to Organizations via RBID_ORG = RBID (one-to-one, company-level only)
  • People can join to Insights via RBID_ORG = RBID_ORG (many-to-one, gets company-level insights)
  • Historical Experience joins to People via linkedin_url (one-to-one)

Join keys reference

From tableTo tableJoin keyJoin typeNotes
PER_LATESTORG_LATESTper.RBID_ORG = org.RBIDLEFT JOINNot all contacts have a company
ORG_LATESTINSIGHTS_LATESTorg.RBID = insights.RBID_ORGLEFT JOINAll insights are company-level
PER_LATESTINSIGHTS_LATESTper.RBID_ORG = insights.RBID_ORGLEFT JOINGet company-level insights for contacts
PER_LATESTHISTORICAL_EXPERIENCE_LATESTper.LINKEDIN_URL = he.linkedin_urlLEFT JOINOne profile per LinkedIn URL

Common join patterns

Contacts with company info

The most common join — enriching contacts with their company’s firmographic data:
SELECT
    c.FIRST_NAME,
    c.LAST_NAME,
    c.EMAIL_ADDRESS,
    c.JOB_TITLE,
    co.COMPANY_NAME,
    co.INDUSTRY_LINKEDIN,
    co.EMPLOYEE_COUNT_MAX,
    co.LOCATION_CITY,
    co.LOCATION_STATE_NAME
FROM RELEASES.RELEASE.PER_LATEST c
LEFT JOIN RELEASES.RELEASE.ORG_LATEST co ON c.RBID_ORG = co.RBID
WHERE c.EMAIL_ADDRESS IS NOT NULL;
Use LEFT JOIN (not INNER JOIN) if you want to include contacts that don’t have a company record. Use INNER JOIN if you only want contacts with a known company.

Contacts with company-level insights

SELECT
    c.FIRST_NAME,
    c.LAST_NAME,
    c.EMAIL_ADDRESS,
    c.JOB_TITLE,
    co.COMPANY_NAME,
    i.CRM_TECH_ORG,
    i.SALES_ROLE_COUNT_ORG
FROM RELEASES.RELEASE.PER_LATEST c
LEFT JOIN RELEASES.RELEASE.ORG_LATEST co ON c.RBID_ORG = co.RBID
LEFT JOIN RELEASES.RELEASE.INSIGHTS_LATEST i ON c.RBID_ORG = i.RBID_ORG
WHERE c.EMAIL_ADDRESS IS NOT NULL;

Full join: contacts + companies + insights

SELECT
    c.FIRST_NAME,
    c.LAST_NAME,
    c.JOB_TITLE,
    co.COMPANY_NAME,
    co.INDUSTRY_LINKEDIN,
    co.EMPLOYEE_COUNT_MAX,
    c.EMAIL_ADDRESS,
    c.EMAIL_LAST_VERIFIED_AT,
    i.CRM_TECH_ORG,
    i.LAST_FUNDING_AMOUNT_ORG
FROM RELEASES.RELEASE.PER_LATEST c
LEFT JOIN RELEASES.RELEASE.ORG_LATEST co ON c.RBID_ORG = co.RBID
LEFT JOIN RELEASES.RELEASE.INSIGHTS_LATEST i ON c.RBID_ORG = i.RBID_ORG
WHERE c.EMAIL_ADDRESS IS NOT NULL
ORDER BY c.EMAIL_LAST_VERIFIED_AT DESC;

Contacts with historical experience

SELECT
    c.FIRST_NAME,
    c.LAST_NAME,
    c.EMAIL_ADDRESS,
    he.job_count,
    he.jobs
FROM RELEASES.RELEASE.PER_LATEST c
LEFT JOIN RELEASES.RELEASE.HISTORICAL_EXPERIENCE_LATEST he ON c.LINKEDIN_URL = he.linkedin_url
WHERE c.EMAIL_ADDRESS IS NOT NULL;
Historical experience uses an array structure. Use LATERAL FLATTEN to work with individual positions. See Historical Experience for details.

Gotchas and tips

Not every contact has a linked company. If you use INNER JOIN on ORG_LATEST, you’ll silently drop those contacts. Use LEFT JOIN unless you specifically want to exclude unmatched contacts. Check for RBID_ORG IS NULL to see how many contacts lack company associations.
All emails in the dataset are verified as valid. You don’t need to filter on EMAIL_STATUS = 'VALID' — if an email exists in the dataset, it’s valid. Use EMAIL_LAST_VERIFIED_AT to prioritize recently verified addresses.
All insights are company-level only. When joining insights to contacts, you get the company-level insights associated with the contact’s company (RBID_ORG). There are no contact-level insights.
The historical experience table stores one row per LinkedIn profile with a jobs array. Use LATERAL FLATTEN to work with individual positions. See Historical Experience for examples.
When joining across large tables, always include filter conditions (WHERE clauses) to reduce the working set before the join. Filtering on EMAIL_LAST_VERIFIED_AT, INDUSTRY_LINKEDIN, or EMPLOYEE_COUNT_MAX early will significantly speed up queries.
For common combinations (people + companies, or people + companies + insights), consider using pre-joined tables like VELOCITY_BASE_UNLIMITED_LATEST or VELOCITY_ENHANCED_UNLIMITED_LATEST instead of writing joins yourself. See Pre-Joined Tables for details.

Joining with your own data

You can also join RevenueBase tables with your own internal data in Snowflake. The most common approach is matching on domain:
-- Match your account list against RevenueBase companies by domain
SELECT
    your_accounts.account_name,
    co.COMPANY_NAME,
    co.EMPLOYEE_COUNT_MAX,
    co.INDUSTRY_LINKEDIN
FROM your_database.your_schema.accounts your_accounts
JOIN RELEASES.RELEASE.ORG_LATEST co
  ON LOWER(your_accounts.website_domain) = LOWER(co.DOMAIN);
Always normalize domains when joining — use LOWER() and strip www. prefixes to avoid mismatches. Consider using TRIM() to remove whitespace as well.