Conventions

A few conventions apply across the whole share. Reading this page first will help understand some common tricks in the data model.

The core key: entity, question, year

Almost every data table answers a question about a company in a period:

  • entity_idwho. Joins to entities.
  • question_id (or its string form, canonical_question_id) — what. Joins to questions.
  • yearwhen. The fiscal year the value relates to. The exact period is given by the start / end (or start_date / end_date) columns, since company fiscal years do not always align with calendar years. See Assigning years for more details on how we allocate this.

Versioned tables: always filter to the current view

The data tables in the share are append-only and versioned. When a value is restated — for example a company restates its emissions, or our research process refines a number — we do not overwrite the old row. Instead the old row is closed and a new row is written. Every versioned table carries:

ColumnTypeDescription
valid_fromTIMESTAMP_TZWhen this version of the row became current
valid_toTIMESTAMP_TZWhen this version was superseded. Open-ended for the live row
is_currentBOOLEANTRUE for the latest version of the row

Unless you are doing point-in-time analysis, always filter is_current = TRUE:

SELECT *
FROM NET_PURPOSE.OUTCOMES.ALL_DATA
WHERE is_current = TRUE
  AND entity_id = 12345;

Point-in-time queries

Because the full history is kept, you can reconstruct exactly what the data looked like on any past date. A row was live at time t when valid_from <= t AND valid_to > t:

SELECT *
FROM NET_PURPOSE.OUTCOMES.ALL_DATA
WHERE entity_id = 12345
  AND valid_from <= '2025-06-30'::TIMESTAMP_TZ
  AND valid_to    >  '2025-06-30'::TIMESTAMP_TZ;

For any given table, data-triplet and t this should be a unique row.

This is useful for backtesting: it removes look-ahead bias by showing only what was known at the time.

Reference tables such as questions, units, segments, taxonomy and reporting_standards are plain lookup tables and do not need the is_current filter.

Data classes: reported, derived, estimated

In the combined data-set schema (Revenue & SDI and Outcomes) all rows carry a label describing from which foundation data-set they were produced:

data_origin_class_idLabelMeaning
1ReportedDisclosed directly by the company in a public source
2DerivedCalculated from reported values (for example a ratio or a sum of segments)
3EstimatedModelled by Net Purpose where no disclosure exists

Every row in all_data carries a data_origin_class_id, so you can include or exclude estimated data with a single filter.

Years and year_rank

Companies disclose on different schedules, so “the latest year” differs by entity. Tables that serve latest-value workflows carry a year_rank column: year_rank = 1 is the most recent year available for that entity, 2 the year before, and so on. To get the latest value per company, filter year_rank = 1 instead of hard-coding a year.

Units and currencies

Numeric values are standardised before they reach the share: each question has a standard unit (see questions.unit_id joined to units), and monetary values are converted to USD. Where a table also exposes the originally reported value and unit (for example datapoints), the reported_value / reported_unit_id columns hold the pre-standardisation figures. These unit tables include units representing orders of magnitude of the base unit (e.g million metric tonnes) which is treated as a separate unit for reporting.

Identifiers

entity_id is the Net Purpose identifier and is stable across the whole share. To map to your own universe, join your ISINs to the primary_isin column on entities, or use entity_identifiers for the other schemes (CUSIP, SEDOL, PermID, FIGI, ticker, LEI) per entity.

Year assignment

The year on a datapoint is not simply the calendar year of its end date. Because fiscal years vary between companies, we assign each datapoint to a fiscal year relative to the entity’s own reporting schedule.

The reporting date

Every entity records a reporting_day and reporting_month — the day and month on which its fiscal year ends. For a given datapoint (a fact or a datapoint) we build a nominal reporting date by combining the entity’s reporting_day and reporting_month with the year of the datapoint’s end date:

reporting_date = date(year(end_date), reporting_month, reporting_day)

For example, an entity with reporting_day = 31, reporting_month = 12 and a datapoint ending 2025-11-15 has a nominal reporting date of 2025-12-31.

Assigning the year

We then compare the datapoint’s end_date to this reporting date. There is a 30-day tolerance window before the reporting date to absorb minor reporting variations:

Where the end_date fallsYear assigned
On or after the reporting dateYear of the reporting date
Within the 30 days before the reporting dateYear of the reporting date
More than 30 days before the reporting dateThe prior year

In other words, any end_date later than reporting_date - 30 days is assigned to the reporting date’s year; anything earlier falls back to the year before.

January reporting dates

If the reporting date falls in January, we treat it as belonging to the previous year. This reflects the convention that a fiscal year ending in early January really relates to the year that just closed. For example, a reporting date of 2026-01-31 is assigned to 2025.