Surrogate key for countries
create table countries (
country_id integer
generated by default as identity
not null
primary key,
country_iso_code varchar2(2)
not null
unique,
country_name varchar2(256)
not null,
home_timezone varchar2(256)
not null
)
Table created.
begin
insert into countries ( country_iso_code, country_name, home_timezone )
values ( 'GB', 'United Kingdom', 'Europe/London' );
insert into countries ( country_iso_code, country_name, home_timezone )
values ( 'US', 'USA', 'America/Los_Angeles' );
insert into countries ( country_iso_code, country_name, home_timezone )
values ( 'DE', 'Germany', 'Europe/Berlin' );
insert into countries ( country_iso_code, country_name, home_timezone )
values ( 'IN', 'India', 'Asia/Kolkata' );
commit;
end;
Statement processed.
Lookup table for game statuses
create table game_statuses (
game_status_id varchar2(10)
not null
primary key,
description varchar2(100)
not null
)
Table created.
insert into game_statuses values ( 'SCHEDULED', 'The game is planned' )
1 row(s) inserted.
insert into game_statuses values ( 'COMPLETED', 'The game has finished' )
1 row(s) inserted.
insert into game_statuses values ( 'CANCELLED', 'The game was called off' )
1 row(s) inserted.
commit
Statement processed.
Columns for home/away countries
create table games (
game_id integer
generated by default as identity
not null
primary key
, game_time timestamp
with time zone
not null
, game_status varchar2(10)
references game_statuses
not null
, home_country
references countries
, away_country
references countries
, home_score integer
, away_score integer
, check ( home_country <> away_country )
/**/
)
Table created.
create or replace function get_country_id ( iso_code varchar2 )
return varchar2 as
country_id varchar2(2);
begin
select country_id into country_id
from countries
where country_iso_code = iso_code;
return nvl ( country_id, iso_code );
end;
Function created.
declare
use_columns boolean := true;
store_points boolean := false;
use_utc boolean := false;
procedure ins_game (
game_status varchar2, game_time timestamp with time zone,
home_country varchar2, away_country varchar2,
home_score int, away_score int,
home_points int, away_points int
) as
stmt clob;
begin
stmt := 'insert into games ( game_status, game_time ' ||
case when use_columns then
', home_country, away_country, home_score, away_score '
end ||
case when use_columns and store_points then
', home_points, away_points '
end ||
') values ( :game_status, :game_time ' ||
case when use_utc then
q'[ at time zone 'UTC' ]'
end ||
case when use_columns then
', get_country_id ( :home_country ), get_country_id ( :away_country )
, :home_score, :away_score '
end ||
case when use_columns and store_points then
', :home_points, :away_points '
end ||
')';
dbms_output.put_line ( stmt );
if use_columns and store_points then
execute immediate stmt
using game_status, game_time
, home_country, away_country, home_score, away_score
, home_points, away_points;
elsif use_columns then
execute immediate stmt
using game_status, game_time
, home_country, away_country, home_score, away_score;
else
execute immediate stmt
using game_status, game_time;
end if;
end ins_game;
begin
ins_game (
'COMPLETED', timestamp'2022-11-05 15:00:00 Europe/London', 'GB', 'US', 3, 1, 3, 0
);
ins_game (
'COMPLETED', timestamp'2022-11-05 15:00:00 Europe/Berlin', 'DE', 'IN', 2, 2, 1, 1
);
ins_game (
'COMPLETED', timestamp'2022-11-12 15:00:00 Asia/Kolkata', 'IN', 'GB', 0, 0, 1, 1
);
ins_game (
'COMPLETED', timestamp'2022-11-12 15:00:00 America/Los_Angeles', 'US', 'DE', 1, 4, 0, 3
);
ins_game (
'SCHEDULED', timestamp'2022-11-19 15:00:00 America/Los_Angeles', 'US', 'IN', null, null, null, null
);
ins_game (
'SCHEDULED', timestamp'2022-11-19 15:00:00 Europe/Berlin', 'DE', 'GB', null, null, null, null
);
ins_game (
'SCHEDULED', timestamp'2022-11-26 15:00:00 America/Los_Angeles', 'US', 'GB', null, null, null, null
);
ins_game (
'SCHEDULED', timestamp'2022-11-26 15:00:00 Asia/Kolkata', 'IN', 'DE', null, null, null, null
);
end;
Statement processed.
insert into games ( game_status, game_time , home_country, away_country, home_score, away_score ) values ( :game_status, :game_time , get_country_id ( :home_country ), get_country_id ( :away_country ) , :home_score, :away_score )
insert into games ( game_status, game_time , home_country, away_country, home_score, away_score ) values ( :game_status, :game_time , get_country_id ( :home_country ), get_country_id ( :away_country ) , :home_score, :away_score )
insert into games ( game_status, game_time , home_country, away_country, home_score, away_score ) values ( :game_status, :game_time , get_country_id ( :home_country ), get_country_id ( :away_country ) , :home_score, :away_score )
insert into games ( game_status, game_time , home_country, away_country, home_score, away_score ) values ( :game_status, :game_time , get_country_id ( :home_country ), get_country_id ( :away_country ) , :home_score, :away_score )
insert into games ( game_status, game_time , home_country, away_country, home_score, away_score ) values ( :game_status, :game_time , get_country_id ( :home_country ), get_country_id ( :away_country ) , :home_score, :away_score )
insert into games ( game_status, game_time , home_country, away_country, home_score, away_score ) values ( :game_status, :game_time , get_country_id ( :home_country ), get_country_id ( :away_country ) , :home_score, :away_score )
insert into games ( game_status, game_time , home_country, away_country, home_score, away_score ) values ( :game_status, :game_time , get_country_id ( :home_country ), get_country_id ( :away_country ) , :home_score, :away_score )
insert into games ( game_status, game_time , home_country, away_country, home_score, away_score ) values ( :game_status, :game_time , get_country_id ( :home_country ), get_country_id ( :away_country ) , :home_score, :away_score )
alter session set nls_timestamp_format = ' DD Mon HH24:MI '
Statement processed.
alter session set nls_timestamp_tz_format = ' DD Mon HH24:MI TZR'
Statement processed.
select * from countries
COUNTRY_ID | COUNTRY_ISO_CODE | COUNTRY_NAME | HOME_TIMEZONE |
---|---|---|---|
1 | GB | United Kingdom | Europe/London |
2 | US | USA | America/Los_Angeles |
3 | DE | Germany | Europe/Berlin |
4 | IN | India | Asia/Kolkata |
select * from games
GAME_ID | GAME_TIME | GAME_STATUS | HOME_COUNTRY | AWAY_COUNTRY | HOME_SCORE | AWAY_SCORE |
---|---|---|---|---|---|---|
1 | 05 Nov 15:00 EUROPE/LONDON | COMPLETED | 1 | 2 | 3 | 1 |
2 | 05 Nov 15:00 EUROPE/BERLIN | COMPLETED | 3 | 4 | 2 | 2 |
3 | 12 Nov 15:00 ASIA/KOLKATA | COMPLETED | 4 | 1 | 0 | 0 |
4 | 12 Nov 15:00 AMERICA/LOS_ANGELES | COMPLETED | 2 | 3 | 1 | 4 |
5 | 19 Nov 15:00 AMERICA/LOS_ANGELES | SCHEDULED | 2 | 4 | - | - |
6 | 19 Nov 15:00 EUROPE/BERLIN | SCHEDULED | 3 | 1 | - | - |
7 | 26 Nov 15:00 AMERICA/LOS_ANGELES | SCHEDULED | 2 | 1 | - | - |
8 | 26 Nov 15:00 ASIA/KOLKATA | SCHEDULED | 4 | 3 | - | - |
commit
Statement processed.
All games for a team
select
game_time at time zone team.home_timezone game_time
, game_status, home_score, away_score
, case
when home_country = team.country_id then team.country_iso_code
else oppo.country_iso_code
end home_country
, case
when away_country = team.country_id then team.country_iso_code
else oppo.country_iso_code
end away_country
from games
join countries team
on team.country_id in ( home_country, away_country )
join countries oppo
on oppo.country_id in ( home_country, away_country )/**/
where team.country_iso_code = 'US'
and team.country_iso_code <> oppo.country_iso_code
GAME_TIME | GAME_STATUS | HOME_SCORE | AWAY_SCORE | HOME_COUNTRY | AWAY_COUNTRY |
---|---|---|---|---|---|
05 Nov 08:00 AMERICA/LOS_ANGELES | COMPLETED | 3 | 1 | GB | US |
12 Nov 15:00 AMERICA/LOS_ANGELES | COMPLETED | 1 | 4 | US | DE |
19 Nov 15:00 AMERICA/LOS_ANGELES | SCHEDULED | - | - | US | IN |
26 Nov 15:00 AMERICA/LOS_ANGELES | SCHEDULED | - | - | US | GB |
SQL macro for country games
create or replace function country_games (
country varchar2
) return clob sql_macro as
begin
return q'!
select
game_time at time zone team.home_timezone game_time
, game_status, home_score, away_score
, case
when home_country = team.country_id then team.country_iso_code
else oppo.country_iso_code
end home_country
, case
when away_country = team.country_id then team.country_iso_code
else oppo.country_iso_code
end away_country /**/
from games
join countries team
on team.country_id in ( home_country, away_country )
join countries oppo
on oppo.country_id in ( home_country, away_country )
where team.country_iso_code = country
and team.country_iso_code <> oppo.country_iso_code
!';
end country_games;
Function created.
select * from country_games ( 'IN' )
GAME_TIME | GAME_STATUS | HOME_SCORE | AWAY_SCORE | HOME_COUNTRY | AWAY_COUNTRY |
---|---|---|---|---|---|
05 Nov 19:30 ASIA/KOLKATA | COMPLETED | 2 | 2 | DE | IN |
12 Nov 15:00 ASIA/KOLKATA | COMPLETED | 0 | 0 | IN | GB |
20 Nov 04:30 ASIA/KOLKATA | SCHEDULED | - | - | US | IN |
26 Nov 15:00 ASIA/KOLKATA | SCHEDULED | - | - | IN | DE |
select * from country_games ( 'DE' )
GAME_TIME | GAME_STATUS | HOME_SCORE | AWAY_SCORE | HOME_COUNTRY | AWAY_COUNTRY |
---|---|---|---|---|---|
05 Nov 15:00 EUROPE/BERLIN | COMPLETED | 2 | 2 | DE | IN |
13 Nov 00:00 EUROPE/BERLIN | COMPLETED | 1 | 4 | US | DE |
19 Nov 15:00 EUROPE/BERLIN | SCHEDULED | - | - | DE | GB |
26 Nov 10:30 EUROPE/BERLIN | SCHEDULED | - | - | IN | DE |
All games for GB including outcome for completed games
select
game_time
, home_country, away_country
, home_score, away_score
, case
when game_status <> 'COMPLETED' then 'TBC'
when home_score = away_score then 'D'
when home_score > away_score and home_country = 'GB' then 'W'
when home_score < away_score and away_country = 'GB' then 'W'
else 'L'
end result
from country_games ( 'GB' )
order by game_time
GAME_TIME | HOME_COUNTRY | AWAY_COUNTRY | HOME_SCORE | AWAY_SCORE | RESULT |
---|---|---|---|---|---|
05 Nov 15:00 EUROPE/LONDON | GB | US | 3 | 1 | W |
12 Nov 09:30 EUROPE/LONDON | IN | GB | 0 | 0 | D |
19 Nov 14:00 EUROPE/LONDON | DE | GB | - | - | TBC |
26 Nov 23:00 EUROPE/LONDON | US | GB | - | - | TBC |
List all fixtures
select game_time at local game_time
, home_country, away_country
from games
GAME_TIME | HOME_COUNTRY | AWAY_COUNTRY |
---|---|---|
05 Nov 08:00 US/PACIFIC | 1 | 2 |
05 Nov 07:00 US/PACIFIC | 3 | 4 |
12 Nov 01:30 US/PACIFIC | 4 | 1 |
12 Nov 15:00 US/PACIFIC | 2 | 3 |
19 Nov 15:00 US/PACIFIC | 2 | 4 |
19 Nov 06:00 US/PACIFIC | 3 | 1 |
26 Nov 15:00 US/PACIFIC | 2 | 1 |
26 Nov 01:30 US/PACIFIC | 4 | 3 |
create or replace function fixtures
return clob sql_macro as
begin
return q'!
select
game_time at local game_time
, home_country, away_country
from games!';
end fixtures;
Function created.
Fixtures for next 7 days in session time zone
select game_time
, home.country_iso_code home_country, away.country_iso_code away_country
from table ( fixtures )
join countries home
on home_country = home.country_id
join countries away
on away_country = away.country_id
where game_time >= timestamp'2022-11-16 00:00:00 UTC'
and game_time < timestamp'2022-11-23 00:00:00 UTC'
order by game_time
GAME_TIME | HOME_COUNTRY | AWAY_COUNTRY |
---|---|---|
19 Nov 06:00 US/PACIFIC | DE | GB |
19 Nov 15:00 US/PACIFIC | US | IN |
alter session set time_zone = 'Europe/Berlin'
Statement processed.
select game_time
, home.country_iso_code home_country, away.country_iso_code away_country
from table ( fixtures )
join countries home
on home_country = home.country_id
join countries away
on away_country = away.country_id
where game_time >= timestamp'2022-11-16 00:00:00 UTC'
and game_time < timestamp'2022-11-23 00:00:00 UTC'
order by game_time
GAME_TIME | HOME_COUNTRY | AWAY_COUNTRY |
---|---|---|
19 Nov 15:00 EUROPE/BERLIN | DE | GB |
20 Nov 00:00 EUROPE/BERLIN | US | IN |
alter session set time_zone = 'Asia/Kolkata'
Statement processed.
select game_time
, home.country_iso_code home_country, away.country_iso_code away_country
from table ( fixtures )
join countries home
on home_country = home.country_id
join countries away
on away_country = away.country_id
where game_time >= timestamp'2022-11-16 00:00:00 UTC'
and game_time < timestamp'2022-11-23 00:00:00 UTC'
order by game_time
GAME_TIME | HOME_COUNTRY | AWAY_COUNTRY |
---|---|---|
19 Nov 19:30 ASIA/KOLKATA | DE | GB |
20 Nov 04:30 ASIA/KOLKATA | US | IN |
alter session set time_zone = 'Europe/London'
Statement processed.
Summary of results per country
with rws as (
select home_country, away_country
, ( home_score - away_score ) as home_diff
, ( away_score - home_score ) as away_diff
, case
when home_score > away_score then 'W'
when home_score = away_score then 'D'
when home_score < away_score then 'L'
end home_wdl
, case
when home_score > away_score then 'L'
when home_score = away_score then 'D'
when home_score < away_score then 'W'
end away_wdl
, case
when home_score > away_score then 3
when home_score = away_score then 1
when home_score < away_score then 0
end home_points
, case
when home_score > away_score then 0
when home_score = away_score then 1
when home_score < away_score then 3
end away_points /**/
from games
where game_status = 'COMPLETED'
)
select country
, sum ( points ), listagg ( wdl ) games, sum ( score_diff ) score_diff
from rws
unpivot (
( country, points, wdl, score_diff ) for home_away in (
( home_country, home_points, home_wdl, home_diff ) as 'HOME',
( away_country, away_points, away_wdl, away_diff ) as 'AWAY'
)
)
group by country
COUNTRY | SUM(POINTS) | GAMES | SCORE_DIFF |
---|---|---|---|
1 | 4 | WD | 2 |
2 | 0 | LL | -5 |
3 | 4 | DW | 3 |
4 | 2 | DD | 0 |
SQL macro of country summary
create or replace function country_results
return clob sql_macro as
begin
return q'!
with rws as (
select home_country, away_country
, ( home_score - away_score ) as home_diff
, ( away_score - home_score ) as away_diff
, case
when home_score > away_score then 'W'
when home_score = away_score then 'D'
when home_score < away_score then 'L'
end home_wdl
, case
when home_score > away_score then 'L'
when home_score = away_score then 'D'
when home_score < away_score then 'W'
end away_wdl
, case
when home_score > away_score then 3
when home_score = away_score then 1
when home_score < away_score then 0
end home_points
, case
when home_score > away_score then 0
when home_score = away_score then 1
when home_score < away_score then 3
end away_points
from games
where game_status = 'COMPLETED'
)
select country
, points, wdl, score_diff
from rws
unpivot (
( country, points, wdl, score_diff ) for home_away in (
( home_country, home_points, home_wdl, home_diff ) as 'HOME',
( away_country, away_points, away_wdl, away_diff ) as 'AWAY'
)
)!';
end country_results;
Function created.
select * from table ( country_results )
COUNTRY | POINTS | WDL | SCORE_DIFF |
---|---|---|---|
1 | 3 | W | 2 |
2 | 0 | L | -2 |
3 | 1 | D | 0 |
4 | 1 | D | 0 |
4 | 1 | D | 0 |
1 | 1 | D | 0 |
2 | 0 | L | -3 |
3 | 3 | W | 3 |
select * from table ( country_results )
pivot (
count(*) c
, sum ( score_diff ) diff
, sum ( points ) points
for wdl in ( 'W' W, 'D' D, 'L' L )
)
COUNTRY | W_C | W_DIFF | W_POINTS | D_C | D_DIFF | D_POINTS | L_C | L_DIFF | L_POINTS |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 3 | 1 | 0 | 1 | 0 | - | - |
2 | 0 | - | - | 0 | - | - | 2 | -5 | 0 |
4 | 0 | - | - | 2 | 0 | 2 | 0 | - | - |
3 | 1 | 3 | 3 | 1 | 0 | 1 | 0 | - | - |
create or replace function league
return clob sql_macro as
begin
return q'!
select * from table ( country_results )
pivot (
count(*) c
, sum ( score_diff ) diff
, sum ( points ) points
for wdl in ( 'W' W, 'D' D, 'L' L )
)
!';
end league;
Function created.
Final league
select country_name, w_c w, d_c d, l_c l,
nvl ( w_points, 0 ) + nvl ( d_points, 0 ) points,
nvl ( w_diff, 0 ) + nvl ( d_diff, 0 ) + nvl ( l_diff, 0 ) score_diff
from table ( league )
join countries
on country = country_id
order by points desc, score_diff desc
COUNTRY_NAME | W | D | L | POINTS | SCORE_DIFF |
---|---|---|---|---|---|
Germany | 1 | 1 | 0 | 4 | 3 |
United Kingdom | 1 | 1 | 0 | 4 | 2 |
India | 0 | 2 | 0 | 2 | 0 |
USA | 0 | 0 | 2 | 0 | -5 |
update games
set game_status = 'ABANDONED'
where game_id = 4
ORA-02291: integrity constraint (SQL_PEKKHYFMLUAYMNXDSCFZPTRAM.SYS_C00103263466) violated - parent key not found ORA-06512: at "SYS.DBMS_SQL", line 1721More Details: https://docs.oracle.com/error-help/db/ora-02291
Add new game status
insert into game_statuses
values ( 'ABANDONED', 'The game was stopped' )
1 row(s) inserted.
update games
set game_status = 'ABANDONED'
where game_id = 4
1 row(s) updated.
commit
Statement processed.
alter table games
add constraint game_statuses_c
check (
game_status in ( 'SCHEDULED', 'COMPLETED', 'CANCELLED', 'ABANDONED' )
)
Table altered.
select /*+ gather_plan_statistics */* from games
where game_status = 'JUNK'
no data found
Check constraints can give better optimizations
select *
from table(dbms_xplan.display_cursor(:LIVESQL_LAST_SQL_ID, null, 'ALLSTATS LAST'))
PLAN_TABLE_OUTPUT |
---|
SQL_ID 5rawstq6mun1b, child number 0 |
------------------------------------- |
select /*+ gather_plan_statistics */* from games where game_status = |
'JUNK' |
Plan hash value: 3673685358 |
---------------------------------------------------------------------------- |
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | |
---------------------------------------------------------------------------- |
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.01 | |
|* 1 | FILTER | | 1 | | 0 |00:00:00.01 | |
|* 2 | TABLE ACCESS FULL| GAMES | 0 | 1 | 0 |00:00:00.01 | |
---------------------------------------------------------------------------- |
Predicate Information (identified by operation id): |
--------------------------------------------------- |
1 - filter(NULL IS NOT NULL) |
2 - filter("GAME_STATUS"='JUNK') |
Note |
----- |
- dynamic statistics used: dynamic sampling (level=2) |