5.1 — Attributes overview
Attributes make data usable across all FOCUS datasets, regardless of origin. The reference is in v1.2 here: focus.finops.org/…/v1-2/#attributes.
5.2 — Column Handling
Naming and ordering conventions for columns. Consistent names mean SQL is portable across all FOCUS sources.
Column name rules
- Column IDs MUST use Pascal case (
ResourceId, notresource_id). - Column IDs MUST NOT use abbreviations (exceptions:
IdandSku). - Column IDs MUST be alphanumeric — no special characters.
- Column IDs SHOULD NOT use acronyms.
- Column IDs SHOULD NOT exceed 50 characters.
- Columns with both an ID and a Name MUST use the
IdorNamesuffix. - Columns with the
Categorysuffix MUST be normalized.
Column order rules
- All FOCUS columns SHOULD appear first in the dataset.
- Custom columns SHOULD appear after all FOCUS columns and SHOULD NOT be intermixed.
Examples
| Column | Status | Note |
|---|---|---|
ResourceId | Valid | Pascal case, allowed Id abbreviation. |
Resource_Id | Invalid | Snake case → should be ResourceId. |
BillingAcctId | Invalid | Uses abbreviation “Acct” → BillingAccountId. |
SKUID | Invalid | All caps → SkuId. |
5.3 — Null Handling
FOCUS columns MUST use null when there’s no value — not empty strings, not 0, not "Not Applicable". Each column’s Content Constraints section indicates whether it allows nulls.
- Always use
IS NULL/IS NOT NULLfor null checks. - Never use
= ''or= 0as a missing-value check. - Use
COALESCE()/IFNULLin calculations.
5.4 — Numeric Format
All numeric columns MUST contain a single numeric value. Allowed: integers, decimals, scientific notation. Forbidden: ranges, arrays, fractional notation (1/2), thousands separators, currency symbols, units of measure, positive signs (+). Negative signs are allowed.
| Allowed | Not allowed |
|---|---|
87090, 1.259, -100.2, 35.2E-7 | 1 ½, $32, +333, 32 GiB, 3,432,342, [3,5,8] |
5.5 — Date/Time Format
All date/time values MUST be in UTC, conform to ISO 8601, and end with Z:
YYYY-MM-DDTHH:mm:ssZ
- Valid:
2026-01-01T00:00:00Z,2026-06-15T14:30:45Z - Invalid:
01/01/2026(wrong format),2026-01-01T00:00:00(missing Z),2026-01-01T00:00:00-05:00(offset, not Z).
5.6 — Currency Format
Currency columns MUST use a three-letter alphabetic code per ISO 4217:2015 (USD, EUR, JPY). Two currency types:
- National currency — government-issued legal tender.
- Virtual currency — provider credits or tokens (Databricks DBUs, OpenAI tokens, …) — introduced in v1.2.
Billing Currency must always be a national currency. Virtual currency may appear in Pricing Currency.
5.7 — String Handling
- String values MUST maintain original casing, spacing, and consistency.
- Mutable references (e.g., resource names) MUST be reflected in subsequent charges and MUST NOT alter charges incurred before the change — preserves historical integrity.
- Immutable references (resource IDs, region IDs) MUST remain consistent across all billing periods.
- Empty / whitespace-only strings SHOULD NOT appear in non-nullable columns.
- Exception: when Charge Class is
Correction, a record may contain an altered mutable value.
Practical rule: join on immutable IDs, not mutable names. Use Resource ID for long-term tracking; use Resource Name for display.
5.8 — Discount Handling
- All applicable discounts SHOULD be applied to each row they pertain to and SHOULD NOT be negated in a separate row.
- Purchased discounts (commitment-based) MUST be amortised.
- Credits applied after the fact use
ChargeCategory = "Credit".
Discount methods directly impact savings calculations. Some providers show list-price usage rows then subtract discounts in separate rows (causing double-count); others apply inline. Misunderstanding this can inflate “we saved $X” reports by 2–10×.
5.9 — Key-Value Format (Tags)
The most common Key-Value column is Tags. Format relies on JSON (ECMA 404):
- Key-Value columns MUST contain a serialized JSON object.
- Keys MUST be unique within an object.
- Values MUST be one of:
number,string,true,false,null. - Values MUST NOT be an object or an array.
{"team":"ops", "env":"prod", "owner":"finops", "review":null}
5.10 — Unit Format
Unit values follow one of three composite patterns:
<plural-units>— e.g.GB(abbreviations cover singular & plural),Seconds<singular-units>-<plural-time-units>— e.g.GB-Hours,MB-Days<plural-units>/<singular-time-unit>— e.g.GB/Hour,PB/Day
Valid time-based units
Year, Month, Day, Hour, Minute, Second. Week is NOT a valid time-based unit.
Naming rules
- Data-size units are abbreviated:
TB, notterabyte.GBcovers both singular and plural —GBsis invalid. - Composite units use
/and space — notperor-alone.
5.11 — Metadata
FOCUS metadata tells you how to work with billing data before you load it. Two entities:
- Data Generator — human-readable name of the generating entity. Example:
{"DataGenerator":"Acme"} - Schema — required for every dataset. Includes: Schema ID, Creation Date, FOCUS Version, Column Definition (Column Name, Data Type, plus optional Numeric Precision & Scale, Provider Tag Prefixes, String Encoding, String Max Length).
For cloud billing data, consider precision 30 / scale 15 — you’ll work with many small numbers that compose into very large totals.
Knowledge check
Q. A new data engineer joins your team and writes a small script to query “all resources missing a name”. They use WHERE ResourceName = '' and get zero results — even though half the fleet has no name set. What’s wrong?
IS NULL. FOCUS Null Handling requires nullable columns to use null for absent values — never empty strings, never placeholder text like "Not Applicable", never 0 for numeric columns. Filtering with = '' matches actual empty strings (which a conformant generator won’t emit) and silently misses every null. Same applies to aggregations — use COALESCE() / IFNULL to keep nulls from skewing results.