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
| Table | Entity Type | Key Columns |
|---|---|---|
CustomerAddressbook | Customer | entity, addressbookaddress, defaultshipping, defaultbilling, label |
VendorAddressbook | Vendor | Same pattern |
EmployeeAddressbook | Employee | Same pattern |
EntityAddress | All entities | nkey, addr1, addr2, addr3, city, state, zip, country, addressee, attention |
CustomerAddressbookEntityAddress | Customer (alternative) | Same as EntityAddress |
VendorAddressbookEntityAddress | Vendor (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
| Table | Purpose | Key Columns |
|---|---|---|
TransactionShippingAddress | Shipping address snapshot | nkey, addr1, addr2, city, state, zip, country, addressee |
TransactionBillingAddress | Billing address snapshot | Same 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
| Type | UI Selection | Saved To | Updates When Customer Changes? |
|---|---|---|---|
| Entity Default | Select existing address | References addressbook | Yes, until transaction is saved |
| New | "New" option | Customer record + Transaction | No (becomes snapshot after save) |
| Custom | "Custom" option | Transaction ONLY | No (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
- Snapshot Tables Overview - Understanding the snapshot pattern
- BOM Tables - Similar pattern for BOM components
- Other Snapshots - Prices, rates, and other snapshotted fields