Back to feed

Project docs

Ski Jumping Statistics

PostgreSQL analysis of men's Ski Jumping World Cup results, supported by a Python data collection pipeline.

World Cup Standings

A season-long classification based on the World Cup points accumulated by each athlete across individual competitions.

Rules

  • World Cup points from every individual competition are summed for each athlete within a season.
  • Final positions are assigned by ranking athletes by their accumulated points.

The calculation reuses the competition_results materialized view, where World Cup points have already been assigned for every competition.

Assigning competitions to seasons

Before results can be aggregated, each competition needs to belong to a season. A stored generated column derives that value from competition_started.

This project uses a deliberately simple boundary: January through June belongs to the season that began in the previous year, while July through December begins the next season. This is a modelling convention rather than an official World Cup rule.

alter table competitions
add column season varchar(50) generated always as (
	case
		when extract(month from competition_started at time zone 'UTC') <= 6 then
			(extract(year from competition_started at time zone 'UTC') - 1) ||
			'/' ||
			extract(year from competition_started at time zone 'UTC')
		else
			extract(year from competition_started at time zone 'UTC') ||
			'/' ||
			(extract(year from competition_started at time zone 'UTC') + 1)
	end
) stored;

Calculating the standings

The world_cups view sums competition points for each athlete within a season, then assigns positions based on the resulting total.

create view world_cups
as
with score_by_jumper as (
	select 
		c.season, 
		cr.jumper_id, 
		sum(cr.score) as total_score
	from competition_results cr
	join competitions c USING (race_id)
	group by c.season, cr.jumper_id
)
select
	sbj.season,
	sbj.jumper_id,
	sbj.total_score,
	rank() over (partition by season order by total_score desc) as pos
from score_by_jumper sbj;

Raw view presentation

First 20 raw world_cups view results20 rows
seasonjumper_idtotal_scorepos
2017/20186514431
2017/20186710702
2017/2018689853
2017/2018668814
2017/2018768405
2017/2018728286
2017/2018818217
2017/2018776658
2017/2018736339
2017/20187859710
2017/20186456811
2017/20188849612
2017/20188042713
2017/20187142713
2017/20188341315
2017/20187040316
2017/201812237917
2017/20187432718
2017/20189731219
2017/20188728020

2017/2018 World Cup standings

The raw view can be joined with athlete data to present the final classification for a selected season.

select 
	wc.pos as no,
	j.jumper_name as jumper,
	wc.total_score
from world_cups wc
join jumpers j using (jumper_id)
where season = '2017/2018'
order by total_score desc;

Results

2017/2018 World Cup standings returned by PostgreSQL109 rows
nojumpertotal_score
1STOCH Kamil1443
2FREITAG Richard1070
3TANDE Daniel Andre985
4KRAFT Stefan881
5JOHANSSON Robert840
6WELLINGER Andreas828
7FORFANG Johann Andre821
8STJERNEN Andreas665
9KUBACKI Dawid633
10EISENBICHLER Markus597
11KOBAYASHI Junshiro568
12FANNEMEL Anders496
13HULA Stefan427
13GEIGER Karl427
15PREVC Peter413
16ZYLA Piotr403
17DAMJAN Jernej379
18LEYHE Stephan327
19AMMANN Simon312
20GRANERUD Halvor Egner280
21KOT Maciej261
22SEMENIC Anze256
23HAYBOECK Michael245
24KOBAYASHI Ryoyu187
25BARTOL Tilen185
26KASAI Noriaki164
27FETTNER Manuel137
28HUBER Daniel117
29AIGNER Clemens104
30PASCHKE Pius90
31TAKEUCHI Taku89
32ZAJC Timi88
33PREVC Domen81
33SCHMID Constantin81
35SCHLIERENZAUER Gregor77
36WOLNY Jakub73
37POPPINGER Manuel66
38DESCHWANDEN Gregor54
39DEZMAN Nejc50
39BICKNER Kevin50
41LINDVIK Marius49
42KORNILOV Denis46
43WANK Andreas45
44JELAR Ziga43
45SATO Yukiya41
46ASCHENWALD Philipp34
47BOYD-CLOWES Mackenzie31
48KOZISEK Cestmir30
49KRANJEC Robert26
50TEPES Jurij22
51ALTENBURGER Florian20
52ZOGRAFSKI Vladimir15
53NAGLIC Tomaz14
54AALTO Antti13
54PEIER Killian13
54PAVLOVCIC Bor13
57RHOADS William12
57KOUDELKA Roman12
59INSAM Alex11
59SIEGEL David11
61RINGEN Sondre9
61WOHLGENANNT Ulrich9
63LEAROYD Jonathan8
63ITO Daiki8
65KLIMOV Evgeniy7
66NOUSIAINEN Eetu6
67DESCOMBES SEVOIE Vincent4
68STURSA Vojtech3
69VASSILIEV Dimitry2
69SCHULER Andreas2
69LEITNER Clemens2
69NAKAMURA Naoki2
73PILCH Tomasz1
73COLLOREDO Sebastian1
75ROMASHOV Alexey0
75HILDE Tom0
75LANISEK Anze0
75GLASDER Michael0
75POLASEK Viktor0
75PEDERSEN Robin0
75BRESADOLA Davide0
75SOKOLENKO Konstantin0
75AIGRO Artti0
75TROFIMOV Roman Sergeevich0
75HLAVA Lukas0
75MAKSIMOCHKIN Mikhail0
75WASEK Pawel0
75ZNISZCZOL Aleksander0
75HARADA Yumu0
75SAKUYAMA Kento0
75NAITO Tomofumi0
75HAZETDINOV Ilmir0
75VANCURA Tomas0
75SCHIFFNER Markus0
75EGLOFF Luca0
75CECON Federico0
75NAZAROV Mikhail0
75PREVC Cene0
75LACKNER Thomas0
75ASIKAINEN Lauri0
75AHONEN Janne0
75KORHONEN Janne0
75ALAMOMMO Andreas0
75MAEAETTAE Jarkko0
75TOLLINGER Elias0
75NOMME Martti0
75HAUSWIRTH Sandro0
75CZYZ Bartosz0
75BJOERENG Joacim Oedegaard0

Additional notes

In the event of a tie for the overall World Cup victory, the winner is determined by the number of wins, followed by second places, third places, and so on. This has happened only once and is omitted here because such logic would be too complex for a single SQL query.