Skip to main content

Address Tables

The most common confusion in NetSuite: "Why doesn't my transaction show the updated customer address?"


Entity Address Tables (Master)

Addresses stored on Customer, Vendor, and Employee records.

ENTITY ADDRESS STRUCTURE
═══════════════════════════════════════════════════════════════════════════════

Customer Record Addressbook (Junction) Address Data
┌───────────────────┐ ┌───────────────────────┐ ┌─────────────────┐
│ Customer ID: 100 │ │ CustomerAddressbook │ │ EntityAddress │
│ Name: Acme Corp │────────▶│ entity: 100 │───────▶│ nkey: 5001 │
│ │ │ addressbookaddress: │ │ addr1: 123 Main │
│ defaultshipping ──┼────────▶│ 5001 │ │ city: New York │
│ defaultbilling ──┼────────▶│ defaultshipping: T │ │ state: NY │
└───────────────────┘ │ label: "Headquarters" │ │ zip: 10001 │
└───────────────────────┘ └─────────────────┘

Entity Address Table Reference

TableEntity TypeKey Columns
CustomerAddressbookCustomerentity, addressbookaddress, defaultshipping, defaultbilling, label
VendorAddressbookVendorSame pattern
EmployeeAddressbookEmployeeSame pattern
EntityAddressAll entitiesnkey, addr1, addr2, addr3, city, state, zip, country, addressee, attention
CustomerAddressbookEntityAddressCustomer (alternative)Same as EntityAddress
VendorAddressbookEntityAddressVendor (alternative)Same as EntityAddress

Query: Customer with All Addresses

SELECT
c.id AS customer_id,
c.companyname,
cab.label AS address_label,
CASE WHEN cab.defaultshipping = 'T' THEN 'Yes' ELSE 'No' END AS is_default_ship,
CASE WHEN cab.defaultbilling = 'T' THEN 'Yes' ELSE 'No' END AS is_default_bill,
ea.addr1,
ea.addr2,
ea.city,
ea.state,
ea.zip,
BUILTIN.DF(ea.country) AS country
FROM Customer c
LEFT JOIN CustomerAddressbook cab ON cab.entity = c.id
LEFT JOIN EntityAddress ea ON ea.nkey = cab.addressbookaddress
WHERE c.isinactive = 'F'
ORDER BY c.companyname, cab.label

Transaction Address Tables (Snapshot)

Addresses stored directly on transactions - these are the snapshots that don't update.

TRANSACTION ADDRESS STRUCTURE
═══════════════════════════════════════════════════════════════════════════════

Transaction Record Address Subrecords (SNAPSHOTS)
┌─────────────────────────────┐ ┌────────────────────────────┐
│ Transaction ID: 12345 │ │ TransactionShippingAddress │
│ Type: SalesOrd │ │ nkey: 8001 │
│ │ │ addr1: 123 Main St │
│ shippingaddress: 8001 ──────┼──────────▶│ city: New York │
│ billingaddress: 8002 ──────┼───┐ │ state: NY │
│ │ │ │ zip: 10001 │
│ shipaddresslist: 5001 │ │ └────────────────────────────┘
│ (original reference) │ │
│ │ │ ┌────────────────────────────┐
└─────────────────────────────┘ │ │ TransactionBillingAddress │
└──────▶│ nkey: 8002 │
│ addr1: 456 Oak Ave │
│ city: Boston │
└────────────────────────────┘

Transaction Address Table Reference

TablePurposeKey Columns
TransactionShippingAddressShipping address snapshotnkey, addr1, addr2, city, state, zip, country, addressee
TransactionBillingAddressBilling address snapshotSame structure

Query: Transaction with Addresses

SELECT
t.id,
t.tranid,
t.trandate,
BUILTIN.DF(t.entity) AS customer,
-- Shipping Address (Snapshot)
tsa.addressee AS ship_to,
tsa.addr1 AS ship_addr1,
tsa.city AS ship_city,
tsa.state AS ship_state,
tsa.zip AS ship_zip,
-- Billing Address (Snapshot)
tba.addressee AS bill_to,
tba.addr1 AS bill_addr1,
tba.city AS bill_city,
tba.state AS bill_state,
tba.zip AS bill_zip
FROM Transaction t
LEFT JOIN TransactionShippingAddress tsa ON tsa.nkey = t.shippingaddress
LEFT JOIN TransactionBillingAddress tba ON tba.nkey = t.billingaddress
WHERE t.type = 'SalesOrd'
ORDER BY t.trandate DESC

The Three Address Types on Transactions

TypeUI SelectionSaved ToUpdates When Customer Changes?
Entity DefaultSelect existing addressReferences addressbookYes, until transaction is saved
New"New" optionCustomer record + TransactionNo (becomes snapshot after save)
Custom"Custom" optionTransaction ONLYNo (transaction-specific)
Automatic Conversion to Custom

When you modify an address on a customer record AFTER it was used on a transaction, NetSuite automatically converts the transaction's address to "Custom" to preserve the original. This is why old transactions keep the old address.


Why Invoice Shows Old Address (Explained)

THE INVOICE ADDRESS INHERITANCE PROBLEM
═══════════════════════════════════════════════════════════════════════════════

Step 1: Sales Order Created (Jan 1)
┌──────────────────────────────┐
│ Sales Order SO-001 │
│ Customer: Acme Corp │
│ Ship To: 123 Main St ◄───────┼─── Copied from customer default
│ │
└──────────────────────────────┘

Step 2: Customer Address Updated (Feb 1)
┌──────────────────────────────┐
│ Customer: Acme Corp │
│ New Address: 999 New Ave ◄───┼─── Address changed in master
│ │
└──────────────────────────────┘


┌──────────────────────────────┐
│ Sales Order SO-001 │
│ Ship To: 123 Main St ◄───────┼─── Auto-converted to CUSTOM
│ (Now marked as Custom) │ to preserve original
└──────────────────────────────┘

Step 3: Invoice Created from SO (Mar 1)
┌──────────────────────────────┐
│ Invoice INV-001 │
│ Created From: SO-001 │
│ Ship To: 123 Main St ◄───────┼─── Inherited from SO's snapshot!
│ │ NOT from current customer address
└──────────────────────────────┘

Result: Invoice shows OLD address (123 Main St)
even though customer now has NEW address (999 New Ave)

Query Examples

Compare Customer Address vs Transaction Address

-- Find transactions where address differs from current customer default
SELECT
t.tranid,
t.trandate,
c.companyname,
-- Current customer address
cur_addr.addr1 AS current_customer_addr,
cur_addr.city AS current_customer_city,
-- Transaction snapshot address
tsa.addr1 AS transaction_addr,
tsa.city AS transaction_city,
CASE
WHEN cur_addr.addr1 != tsa.addr1 THEN 'ADDRESS CHANGED'
ELSE 'Same'
END AS status
FROM Transaction t
INNER JOIN Customer c ON c.id = t.entity
-- Current default shipping
LEFT JOIN CustomerAddressbook cab ON cab.entity = c.id AND cab.defaultshipping = 'T'
LEFT JOIN EntityAddress cur_addr ON cur_addr.nkey = cab.addressbookaddress
-- Transaction snapshot
LEFT JOIN TransactionShippingAddress tsa ON tsa.nkey = t.shippingaddress
WHERE t.type = 'SalesOrd'
AND cur_addr.addr1 != tsa.addr1
ORDER BY t.trandate DESC

Get All Addresses for a Customer

SELECT
c.companyname,
cab.label,
cab.defaultshipping,
cab.defaultbilling,
ea.addressee,
ea.addr1,
ea.addr2,
ea.city,
ea.state,
ea.zip,
BUILTIN.DF(ea.country) AS country
FROM Customer c
INNER JOIN CustomerAddressbook cab ON cab.entity = c.id
INNER JOIN EntityAddress ea ON ea.nkey = cab.addressbookaddress
WHERE c.id = 100
ORDER BY cab.label

Vendor Addresses with Transactions

SELECT
v.entityid AS vendor_name,
t.tranid AS bill_number,
t.trandate,
tba.addr1 AS bill_address,
tba.city,
tba.state
FROM Vendor v
INNER JOIN Transaction t ON t.entity = v.id AND t.type = 'VendBill'
LEFT JOIN TransactionBillingAddress tba ON tba.nkey = t.billingaddress
WHERE v.id = 500
ORDER BY t.trandate DESC

Common Pitfalls

Pitfall 1: Querying Wrong Table

-- ❌ WRONG: Getting customer's current address for transaction report
SELECT c.defaultshippingaddress
FROM Customer c
INNER JOIN Transaction t ON t.entity = c.id
-- This gives CURRENT address, not what's actually on the transaction

-- ✅ CORRECT: Get the actual transaction address
SELECT tsa.addr1, tsa.city
FROM Transaction t
INNER JOIN TransactionShippingAddress tsa ON tsa.nkey = t.shippingaddress
-- This gives the ACTUAL address stored on the transaction

Pitfall 2: Expecting Automatic Updates

❌ WRONG EXPECTATION:
"I updated the customer address, so all their invoices should show the new address."

✅ REALITY:
Existing transactions keep the original address.
Only NEW transactions use the new address.

Pitfall 3: Using Wrong Join Column

-- ❌ WRONG: Using entity ID to join addresses
LEFT JOIN EntityAddress ea ON ea.entity = c.id

-- ✅ CORRECT: Use addressbookaddress → nkey relationship
LEFT JOIN CustomerAddressbook cab ON cab.entity = c.id
LEFT JOIN EntityAddress ea ON ea.nkey = cab.addressbookaddress

Quick Reference

Entity Address Join Pattern

FROM Customer c
LEFT JOIN CustomerAddressbook cab ON cab.entity = c.id
LEFT JOIN EntityAddress ea ON ea.nkey = cab.addressbookaddress

Transaction Address Join Pattern

FROM Transaction t
LEFT JOIN TransactionShippingAddress tsa ON tsa.nkey = t.shippingaddress
LEFT JOIN TransactionBillingAddress tba ON tba.nkey = t.billingaddress

See Also