Use case

How to build a sector hiring index from company job postings

One large employer can decide a sector index built by summing its postings. Here is how to weight, cap and bound company-level hiring, with SQL on daily data and an illustrative example.

11 min read

To build a sector hiring index from company job postings, you turn many company-level counts into one number that keeps its meaning from one window to the next. This guide takes the five decisions in order, then gives SQL on daily hiring data that builds an equal-weighted and a capped index side by side, an illustrative example and a checklist for sample data.

How do you build a sector hiring index from company job postings?

Start from a fixed set of companies, the same in the base window and in each later one. Measure each company's postings against its own base level, combine the ratios with weights you choose, cap any company's weight, bound extreme ratios, and scale the result so the base period reads 100. Then state what one point means.

Write all five down before the first run.

DecisionChoicesWhat it settles
Which companiesA fixed panel for the whole run, or a matched sample at each step, chainedWhether companies entering or leaving move the index
Sum or averageTotal postings over the total base, or an average of company ratiosWhether the index follows postings or companies
WeightsBase-period postings, equal, capped, or another size measureHow far the largest employers decide the result
OutliersA floor and a ceiling on each company's ratio, and a minimum baseHow far one small company's burst moves the index
BaseA window of days whose average reads 100What one point means

Fix the companies before you count

A sector index shows a trend only when the same companies stand behind the base and the current figure. Add a company with a large board in the current window and the index rises although no employer hired more. Choose the members first, from your own sector classification, and keep the list with the date you drew it.

For listed companies the bridge is the ISIN: the listed securities table carries, for each matched equity listing, its stable Fokals company ID, and mapping alternative data to a security master covers the full join.

select distinct company_id
from listed_securities
where isin in (:sector_isins)
  and company_id is not null;

Then hold the set fixed in one of two ways.

  • A fixed panel. Keep only companies observed on every day from the base window to the latest one. It is simple, but it ages towards the employers that lasted, which is survivorship bias.
  • A chain of matched samples. Compare each window only with the one before it, over the companies present in both, and multiply the links. The US Bureau of Labor Statistics estimates payroll employment this way: its handbook for the Current Employment Statistics survey defines the matched sample as every unit that reported for both the reference month and the month before, and a weighted link relative carries the previous month's estimate forward.

The weekly Market Series hold each cohort fixed in the same spirit, as same-store cohorts explains.

Job postings index methodology: sector aggregation and weighting

Summing the postings of a sector and dividing by the base sum gives a weighted average of each company's change, weighted by its share of base-period postings. Averaging the company ratios instead gives every company one equal vote. The choice between a sum and an average is therefore a choice of weights: make it on purpose and publish both.

aggregate index      = 100 * sum(cur_i) / sum(base_i)
                     = 100 * sum of w_i * r_i,  where w_i = base_i / sum(base_i), r_i = cur_i / base_i
equal-weighted index = 100 * (sum of r_i) / N

The aggregate follows the postings the sector advertises in total, the measure to set beside employment or openings. The equal-weighted index follows the typical company and says how widely a change has spread. When they disagree in sign, a few large employers are moving against the rest, and that is a finding to report.

Official indexes state their weights and what the weights represent. The BLS handbook for the consumer price index derives aggregation weights from household expenditure and describes their function as giving each basic index a relative importance in the aggregate. The Federal Reserve bases the weights of its industrial production index on annual estimates of value added. Breadth is measured apart: the BLS diffusion indexes of payroll employment count the share of industries whose employment rose, add half of those unchanged, and read 50 as an even balance. A postings index can carry both.

Weighting methodology for company-level data: dominance by large employers in a hiring index

In a summed index each company's influence equals its share of base-period postings, so an employer holding most of the sector's postings decides the result alone. Measure that concentration first. Then cap any one company's weight at a set share and pass the excess to the others in proportion to their size, or move to equal weights.

A cap works in rounds. Set every base-period share above the cap to the cap, spread the weight removed over the uncapped companies in proportion to their shares, and repeat until none exceeds it. A cap below one divided by the number of companies cannot be met, so with ten companies the lowest workable cap is 10 per cent. The query further down reaches the end state in one pass.

Statistics offices measure large units fully and limit what one unit stands for. The ONS Monthly Business Survey collects a return from every business above an industry-specific employment threshold for large businesses. The BLS payroll survey can treat a report identified as an outlier as atypical, so that it represents the change in its own establishment and not in others. A cap applies that second idea: the largest employer still counts, at a weight you can defend.

Firm size weighting and an employment concentration index for company-level hiring activity

Firm size weighting counts each company in proportion to a size measure, such as base-period postings or stated headcount. To see how concentrated hiring activity is, compute the Herfindahl-Hirschman index of the companies' shares of base-period postings: the sum of the squared shares. Its inverse is the effective number of companies standing behind the index.

The US Department of Justice computes the measure by squaring each firm's market share and summing the results, so it reaches its maximum of 10,000 points when one firm controls the market, and states that the antitrust agencies generally consider markets above 1,800 points highly concentrated. Those lines are drawn for merger review. For an index the inverse is easier to act on: at a sum of squared shares of 0.25, the index behaves like one built on four equal companies, however many members it has. A headcount weight, from Employee Headcount, ties the index to employment; a base-postings weight ties it to advertised hiring.

Winsorizing and capping outliers: index construction in economic indicator methodology

Bound each company's ratio of current to base postings between a floor and a ceiling, and replace any ratio outside them with the bound. The company stays in the index with its direction intact, but a small employer that went from five postings to thirty can no longer decide an equal-weighted average. Publish the bounds with the index.

Bound the ratio, not the level: trimming large employers is the weight's job. Add a minimum base, below which a ratio is mostly chance, and set the bounds before the first run. A symmetric pair such as 0.5 and 2 treats a halving and a doubling alike.

Statistics offices keep accurate outliers and limit their reach. In the BLS consumer price index, outlier price changes are reviewed and, when accurate, generally included, while extreme price changes are held within upper and lower bounds, for which the handbook gives 10 and 0.1 as an example. The ONS detects outliers in its Monthly Business Survey automatically and treats them by winsorizing, which it describes as limiting extreme values to a statistical boundary, through a weight applied to every return.

The base period, and what one point means

Set the base on a window of 28 days or more, not on a day. The ONS built its experimental weekly index of online job adverts, updated until 24 October 2024, this way: it divided every value by the mean weekly count of live adverts in February 2020, so that month's average reads 100. Most CPI-U and CPI-W indexes of the BLS have a reference base of 1982 to 1984 equal to 100, so a 7 per cent rise from the base shows as 107.

Then say what a point means.

  • Aggregate: one point is 1 per cent of the panel's base level of postings.
  • Equal-weighted: one point is a change of 0.01 in the average company's ratio to its own base.
  • Capped: the same, on the capped weights.

Report changes over time in per cent. The BLS usually expresses movements of its price indexes as percent changes because a change in index points depends on the level of the index relative to its base, and a percent change does not. A move from 108.2 to 110.0 is 1.8 points and 1.7 per cent.

The ONS notes that the number of job adverts is not a direct measure of labour demand and can respond to changes in how positions are recruited for. The BLS job openings rate stands on another base, openings over employment plus openings, so compare a postings index with it by direction.

The queries: equal-weighted and capped indexes side by side

The queries read Hiring Activity, which holds daily open, new and closed postings for each company, written once for each closed UTC day and never revised. Each company is measured by its average open postings per day in a window. Every date, member and bound is a parameter.

ParameterWhat you set
:membersThe sector's company IDs
:base_start, :base_endThe first and last day of the base window
:cur_start, :cur_endThe first and last day of the current window
:base_days, :daysThe number of days in each window
:min_baseThe lowest base level a company may have
:floor, :ceilingThe bounds on each company's ratio
:capThe largest weight any company may carry, at least 1 divided by the number of companies
with windows as (
  select
    company_id,
    avg(case when day between :base_start and :base_end then open_postings end) as base_level,
    avg(case when day between :cur_start and :cur_end then open_postings end)   as cur_level,
    count(case when day between :base_start and :base_end then 1 end)           as base_rows,
    count(case when day between :cur_start and :cur_end then 1 end)             as cur_rows
  from company_hiring_daily
  where company_id in (:members)
    and (day between :base_start and :base_end or day between :cur_start and :cur_end)
  group by company_id
),
panel as (
  select
    company_id, base_level, cur_level,
    least(greatest(cur_level / base_level, :floor), :ceiling) as ratio
  from windows
  where base_rows = :base_days
    and cur_rows = :days
    and base_level >= :min_base
),
ranked as (
  select
    company_id, base_level, ratio,
    row_number() over (order by base_level desc, company_id) as rk,
    sum(base_level) over () as total,
    sum(base_level) over (order by base_level desc, company_id
                          rows between unbounded preceding and current row) as cum
  from panel
),
capped as (
  select coalesce(min(rk) - 1, 0) as k
  from ranked
  where (1 - (rk - 1) * :cap) * base_level / (total - cum + base_level) <= :cap
),
weights as (
  select
    r.ratio,
    case
      when r.rk <= c.k then :cap
      else (1 - c.k * :cap) * r.base_level
           / sum(case when r.rk > c.k then r.base_level end) over ()
    end as w
  from ranked r
  cross join capped c
)
select
  (select count(*) from panel)                                as companies,
  100 * (select sum(cur_level) / sum(base_level) from panel)   as aggregate_index,
  100 * (select avg(ratio) from panel)                         as equal_weighted_index,
  100 * (select sum(w * ratio) from weights)                   as capped_index,
  100 * (select avg(case when cur_level > base_level then 1.0
                         when cur_level = base_level then 0.5
                         else 0 end) from panel)               as diffusion_index;

In company_hiring_daily, open_postings counts the postings open at the end of each closed day. A company enters the panel only with a row for every day of both windows and a base of at least :min_base. The aggregate uses raw levels; the other two use the bounded ratio. The capped step finds how many of the largest companies must sit at the cap, and the rest share what remains in proportion to their base. The last column is a diffusion index over companies.

To measure concentration, end the same query with this select in place of the last one.

select
  10000 * sum(power(base_level / total, 2)) as hhi_points,
  1.0 / sum(power(base_level / total, 2))   as effective_companies,
  max(base_level / total)                   as largest_share
from ranked;

For an index of hiring flow, average new_postings over each window instead. A posting already on a board when a company's postings were first observed is a baseline, never counted as new, so a newly covered company brings no false burst. For a weekly chain of matched samples, run the query with the previous window as the base and multiply: each value is the previous one times the link divided by 100.

An illustrative example: one large employer and four small ones

Assumptions:

  • The panel is five invented companies: Acme Robotics and four smaller companies, B to E.
  • Each has a row on every day of a base window and a current window of 28 days each.
  • Levels are average open postings per day, invented for the example.
  • Ratios are bounded between 0.5 and 2.0, the minimum base is 3 and the cap is 30 per cent.
CompanyBase levelCurrent levelRatioBounded ratioBase shareCapped weight
Acme Robotics4002800.700.700.800.30
B50601.201.200.100.30
C30361.201.200.060.24
D15181.201.200.030.12
E5306.002.000.010.04
Total5004241.001.00
  1. Aggregate: 424 / 500 = 0.848, so the index reads 84.8.
  2. Equal-weighted without bounds: (0.70 + 1.20 + 1.20 + 1.20 + 6.00) / 5 = 2.06, or 206.0. With bounds: (0.70 + 1.20 + 1.20 + 1.20 + 2.00) / 5 = 1.26, or 126.0.
  3. Capping: the share of Acme Robotics, 0.80, exceeds 0.30, so it is capped and 0.70 is left for a base of 100. Company B would take 0.70 × 50 / 100 = 0.35, above the cap, so B is capped too. The remaining 0.40 goes over a base of 50: C takes 0.24, D 0.12 and E 0.04, all below the cap, and the weights sum to 1.
  4. Capped index: 0.21 + 0.36 + 0.288 + 0.144 + 0.08 = 1.082, or 108.2.
  5. Concentration: 6,400 + 100 + 36 + 9 + 1 = 6,546 points, so the effective number of companies is 10,000 / 6,546 = 1.53.
  6. Diffusion: four companies rose and one fell, so the diffusion index reads 80.

Advertised demand in the sector fell 15.2 per cent because its dominant employer cut back, while four of its five companies advertised more. The concentration figure says why the aggregate shows only the first half: the panel behaves like one and a half equal companies. Without bounds, company E, with 1 per cent of base postings, would lift the equal-weighted index from 126.0 to 206.0 alone. A note on this sector reports the aggregate and the capped index together, with the diffusion index beside them.

Checks to run on sample data before you publish

CheckHowPass when
PanelCount the members that enter the panel and list the restEvery exclusion has a reason: a missing day or a base below the minimum
ConcentrationLargest base share and effective number of companiesBoth are reported, and the cap binds wherever the largest share exceeds it
BoundsCount ratios at the floor or the ceilingA few companies at most; many at a bound means the bounds are too tight
Leave one outRerun without the largest companyThe capped index keeps its direction
Late daysCount rows flagged reconstructed in both windowsA strict run without those companies barely moves the index
AgreementSet the aggregate, capped, equal-weighted and diffusion indexes side by sideThey agree in sign, or the note explains why not

Where the weekly Market Series fit

Market Series is the ready-made form of this work: weekly series for industries, countries, company size bands and markets, as of each Sunday, over 7, 30 and 180 days, on same-store cohorts, with an index that reads 100 at each series' first as-of date. Sector hiring trends for macro and thematic research shows how to read them. Build your own from Hiring Activity when the sector, the weights and the cap are yours to set, and read it beside the nearest industry series as a check of direction. The hiring dataset page and the data dictionary define every column used above.

Frequently asked questions

What is the difference between an equal-weighted and a capped hiring index?

An equal-weighted hiring index averages each company's change against its own base, so every company counts once and the index shows how widely hiring moved. A capped index weights companies by their share of base-period postings but holds any one company to a set maximum, passing the excess to the others in proportion to their size. It stays close to total demand while keeping one employer from deciding the result.

How do I stop one large employer from dominating a sector hiring index?

Measure concentration first: the share of base-period postings held by the largest company, and the effective number of companies, which is one divided by the sum of squared shares. Then cap each company's weight at a set share, no lower than one divided by the number of companies, and spread the excess over the others in proportion to their size. Publish the uncapped index beside the capped one.

Should a hiring index use open postings or new postings?

Open postings measure the stock of roles a company advertises, and their average over a window is steady enough to carry an index. New postings measure the flow of roles opened, which turns sooner but is noisier, above all for small companies. A practical pair is a stock index for the level with a flow index beside it as the earlier signal. Hiring Activity counts both for each company and day.

What base period should a job postings index use?

Use a window rather than a single day, such as the average over 28 days or more, set to 100. Choose a period in which every company of the panel was observed throughout, and keep it fixed, because changing the base rescales every value. Report changes in per cent rather than index points, since a move of one point means less the further the index stands above its base.

How do statistics offices treat outliers when they build an index?

They keep accurate outliers and limit their reach. The US Bureau of Labor Statistics reviews outlier price changes in its consumer price index, generally includes accurate ones and holds extreme changes within upper and lower bounds. The UK Office for National Statistics detects outliers in its Monthly Business Survey automatically and treats them by winsorizing. The BLS payroll survey can treat an outlying report so that it represents only the change in its own establishment.

The queries and code on this page are examples to adapt. Test them in your own environment before you rely on them.

What this page says about the products it names was checked against their public documentation on 7 October 2026. Product and company names are trademarks of their owners. Fokals is not affiliated with them or endorsed by them.