Natural key for countries
create table countries (
country_iso_code varchar2(2)
not null
primary key,
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' );
end;
Statement processed.
commit
Statement processed.
UTC for match dates
create table games (
game_id integer
generated by default as identity
not null
primary key
, game_time timestamp
not null
, game_status varchar2(10)
constraint game_status_c check (
game_status in ( 'SCHEDULED', 'COMPLETED', 'CANCELLED' )
)
not null
)
Table created.
Rows for home/away countries
create table game_countries (
game_id
references games
not null
, country_id
references countries
not null
, home_away varchar2(4)
check ( home_away in ( 'HOME', 'AWAY' ) )
not null
, score integer
default on null 0
not null
, points integer
default on null 0
not null
, unique ( game_id, country_id )
, unique ( game_id, home_away )
)
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.
Add games
declare
use_columns boolean := false;
store_points boolean := true;
use_utc boolean := true;
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 ) values ( :game_status, :game_time at time zone 'UTC' )
insert into games ( game_status, game_time ) values ( :game_status, :game_time at time zone 'UTC' )
insert into games ( game_status, game_time ) values ( :game_status, :game_time at time zone 'UTC' )
insert into games ( game_status, game_time ) values ( :game_status, :game_time at time zone 'UTC' )
insert into games ( game_status, game_time ) values ( :game_status, :game_time at time zone 'UTC' )
insert into games ( game_status, game_time ) values ( :game_status, :game_time at time zone 'UTC' )
insert into games ( game_status, game_time ) values ( :game_status, :game_time at time zone 'UTC' )
insert into games ( game_status, game_time ) values ( :game_status, :game_time at time zone 'UTC' )
Add countries per game
begin
insert into game_countries ( game_id, country_id, home_away, score )
values ( 1, get_country_id ( 'GB' ), 'HOME', 3 );
insert into game_countries ( game_id, country_id, home_away, score )
values ( 1, get_country_id ( 'US' ), 'AWAY', 1 );
insert into game_countries ( game_id, country_id, home_away, score )
values ( 2, get_country_id ( 'DE' ), 'HOME', 2 );
insert into game_countries ( game_id, country_id, home_away, score )
values ( 2, get_country_id ( 'IN' ), 'AWAY', 2 );
insert into game_countries ( game_id, country_id, home_away, score )
values ( 3, get_country_id ( 'IN' ), 'HOME', 0 );
insert into game_countries ( game_id, country_id, home_away, score)
values ( 3, get_country_id ( 'GB' ), 'AWAY', 0 );
insert into game_countries ( game_id, country_id, home_away, score
) values ( 4, get_country_id ( 'US' ), 'HOME', 1 );
insert into game_countries ( game_id, country_id, home_away, score )
values ( 4, get_country_id ( 'DE' ), 'AWAY', 4 );
insert into game_countries ( game_id, country_id, home_away )
values ( 5, get_country_id ( 'US' ), 'HOME' );
insert into game_countries ( game_id, country_id, home_away )
values ( 5, get_country_id ( 'IN' ), 'AWAY' );
insert into game_countries ( game_id, country_id, home_away )
values ( 6, get_country_id ( 'DE' ), 'HOME' );
insert into game_countries ( game_id, country_id, home_away )
values ( 6, get_country_id ( 'GB' ), 'AWAY' );
insert into game_countries ( game_id, country_id, home_away )
values ( 7, get_country_id ( 'US' ), 'HOME' );
insert into game_countries ( game_id, country_id, home_away )
values ( 7, get_country_id ( 'GB' ), 'AWAY' );
insert into game_countries ( game_id, country_id, home_away )
values ( 8, get_country_id ( 'IN' ), 'HOME' );
insert into game_countries ( game_id, country_id, home_away )
values ( 8, get_country_id ( 'DE' ), 'AWAY' );
end;
Statement processed.
Set points for completed games
update game_countries g
set points = (
select case
when home_score = away_score then 1
when home_away = 'HOME' and home_score > away_score then 3
when home_away = 'AWAY' and home_score < away_score then 3
else 0
end p
from (
select *
from game_countries c
where g.game_id = c.game_id
)
pivot (
max ( country_id ) country, max ( score ) score
for home_away in ( 'HOME' home, 'AWAY' away )
)
)
where game_id in ( 1, 2, 3, 4 )
8 row(s) updated.
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_ISO_CODE | COUNTRY_NAME | HOME_TIMEZONE | GB | United Kingdom | Europe/London | US | USA | America/Los_Angeles | DE | Germany | Europe/Berlin | IN | India | Asia/Kolkata |
---|
select * from games
GAME_ID | GAME_TIME | GAME_STATUS | 1 | 05 Nov 15:00 | COMPLETED | 2 | 05 Nov 14:00 | COMPLETED | 3 | 12 Nov 09:30 | COMPLETED | 4 | 12 Nov 23:00 | COMPLETED | 5 | 19 Nov 23:00 | SCHEDULED | 6 | 19 Nov 14:00 | SCHEDULED | 7 | 26 Nov 23:00 | SCHEDULED | 8 | 26 Nov 09:30 | SCHEDULED |
---|
select * from game_countries
GAME_ID | COUNTRY_ID | HOME_AWAY | SCORE | POINTS | 1 | GB | HOME | 3 | 3 | 1 | US | AWAY | 1 | 0 | 2 | DE | HOME | 2 | 1 | 2 | IN | AWAY | 2 | 1 | 3 | IN | HOME | 0 | 1 | 3 | GB | AWAY | 0 | 1 | 4 | US | HOME | 1 | 0 | 4 | DE | AWAY | 4 | 3 | 5 | US | HOME | 0 | 0 | 5 | IN | AWAY | 0 | 0 | 6 | DE | HOME | 0 | 0 | 6 | GB | AWAY | 0 | 0 | 7 | US | HOME | 0 | 0 | 7 | GB | AWAY | 0 | 0 | 8 | IN | HOME | 0 | 0 | 8 | DE | AWAY | 0 | 0 |
---|
commit
Statement processed.
All games for a team
select * from (
select
max ( -- get the local time for the country of interest
case when 'US' = country_iso_code then
from_tz ( game_time, 'UTC' ) at time zone home_timezone
end
) over ( partition by game_id ) game_time,
home_away, country_iso_code, score, game_status, game_id
from games
join game_countries
using ( game_id )
join countries
on country_id = country_iso_code
)
pivot (
max ( country_iso_code ) country, max ( score ) score
for home_away in ( 'HOME' home, 'AWAY' away )
) m
where 'US' in ( home_country, away_country )
GAME_TIME | GAME_STATUS | GAME_ID | HOME_COUNTRY | HOME_SCORE | AWAY_COUNTRY | AWAY_SCORE | 05 Nov 08:00 AMERICA/LOS_ANGELES | COMPLETED | 1 | GB | 3 | US | 1 | 12 Nov 15:00 AMERICA/LOS_ANGELES | COMPLETED | 4 | US | 1 | DE | 4 | 19 Nov 15:00 AMERICA/LOS_ANGELES | SCHEDULED | 5 | US | 0 | IN | 0 | 26 Nov 15:00 AMERICA/LOS_ANGELES | SCHEDULED | 7 | US | 0 | GB | 0 |
---|
SQL macro for country games
create or replace function country_games (
country varchar2
) return clob sql_macro as
begin
return q'!
select * from (
select
max ( -- get the local time for the country of interest
case when country = country_iso_code then
from_tz ( game_time, 'UTC' ) at time zone home_timezone
end
) over ( partition by game_id ) game_time,
home_away, country_iso_code, score, game_status, game_id
from games
join game_countries
using ( game_id )
join countries
on country_id = country_iso_code
)
pivot (
max ( country_iso_code ) country, max ( score ) score
for home_away in ( 'HOME' home, 'AWAY' away )
) m
where country in ( home_country, away_country )
!';
end country_games;
Function created.
select * from country_games ( 'IN' )
GAME_TIME | GAME_STATUS | GAME_ID | HOME_COUNTRY | HOME_SCORE | AWAY_COUNTRY | AWAY_SCORE | 05 Nov 19:30 ASIA/KOLKATA | COMPLETED | 2 | DE | 2 | IN | 2 | 12 Nov 15:00 ASIA/KOLKATA | COMPLETED | 3 | IN | 0 | GB | 0 | 20 Nov 04:30 ASIA/KOLKATA | SCHEDULED | 5 | US | 0 | IN | 0 | 26 Nov 15:00 ASIA/KOLKATA | SCHEDULED | 8 | IN | 0 | DE | 0 |
---|
select * from country_games ( 'DE' )
GAME_TIME | GAME_STATUS | GAME_ID | HOME_COUNTRY | HOME_SCORE | AWAY_COUNTRY | AWAY_SCORE | 05 Nov 15:00 EUROPE/BERLIN | COMPLETED | 2 | DE | 2 | IN | 2 | 13 Nov 00:00 EUROPE/BERLIN | COMPLETED | 4 | US | 1 | DE | 4 | 19 Nov 15:00 EUROPE/BERLIN | SCHEDULED | 6 | DE | 0 | GB | 0 | 26 Nov 10:30 EUROPE/BERLIN | SCHEDULED | 8 | IN | 0 | DE | 0 |
---|
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 | 0 | 0 | TBC | 26 Nov 23:00 EUROPE/LONDON | US | GB | 0 | 0 | TBC |
---|
List all fixtures
with rws as (
select game_time, game_id, home_away, country_id
from games
join game_countries
using ( game_id )
)
select
game_time at local game_time
, game_id, home_country, away_country
from rws
pivot (
max ( country_id ) country
for home_away in ( 'HOME' home, 'AWAY' away )
)
GAME_TIME | GAME_ID | HOME_COUNTRY | AWAY_COUNTRY | 12 Nov 09:30 US/PACIFIC | 3 | IN | GB | 19 Nov 14:00 US/PACIFIC | 6 | DE | GB | 19 Nov 23:00 US/PACIFIC | 5 | US | IN | 12 Nov 23:00 US/PACIFIC | 4 | US | DE | 05 Nov 15:00 US/PACIFIC | 1 | GB | US | 26 Nov 23:00 US/PACIFIC | 7 | US | GB | 05 Nov 14:00 US/PACIFIC | 2 | DE | IN | 26 Nov 09:30 US/PACIFIC | 8 | IN | DE |
---|
create or replace function fixtures
return clob sql_macro as
begin
return q'!
with rws as (
select game_time, game_id, home_away, country_id
from games
join game_countries
using ( game_id )
)
select
game_time at local game_time
, game_id, home_country, away_country
from rws
pivot (
max ( country_id ) country
for home_away in ( 'HOME' home, 'AWAY' away )
)!';
end fixtures;
Function created.
Fixtures for next 7 days in session time zone
select game_time
, home_country, away_country
from table ( fixtures )
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 14:00 US/PACIFIC | DE | GB | 19 Nov 23:00 US/PACIFIC | US | IN |
---|
alter session set time_zone = 'Europe/Berlin'
Statement processed.
alter session set time_zone = 'Asia/Kolkata'
Statement processed.
alter session set time_zone = 'Europe/London'
Statement processed.
Summary of results per country
with rws as (
select team.country_id country
, ( team.score - oppo.score ) as score_diff
, case
when team.score > oppo.score then 'W'
when team.score = oppo.score then 'D'
when team.score < oppo.score then 'L'
end wdl
, team.points
from games g
join game_countries team
on g.game_id = team.game_id
join game_countries oppo
on g.game_id = oppo.game_id
and oppo.country_id <> team.country_id
where game_status = 'COMPLETED'
)
select country
, sum ( points ) points, listagg ( wdl ) games, sum ( score_diff ) score_diff
from rws
group by country
COUNTRY | POINTS | GAMES | SCORE_DIFF | DE | 4 | DW | 3 | GB | 4 | WD | 2 | IN | 2 | DD | 0 | US | 0 | LL | -5 |
---|
SQL macro of country summary
create or replace function country_results
return clob sql_macro as
begin
return q'!
with rws as (
select team.country_id country
, ( team.score - oppo.score ) as score_diff
, case
when team.score > oppo.score then 'W'
when team.score = oppo.score then 'D'
when team.score < oppo.score then 'L'
end wdl
/* Uncomment as appropriate */
, team.points
from games g
join game_countries team
on g.game_id = team.game_id
join game_countries oppo
on g.game_id = oppo.game_id
and oppo.country_id <> team.country_id
where game_status = 'COMPLETED'
)
select country
, points, wdl, score_diff
from rws!';
end country_results;
Function created.
select * from table ( country_results )
COUNTRY | POINTS | WDL | SCORE_DIFF | US | 0 | L | -2 | GB | 3 | W | 2 | IN | 1 | D | 0 | DE | 1 | D | 0 | GB | 1 | D | 0 | IN | 1 | D | 0 | DE | 3 | W | 3 | US | 0 | L | -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 | DE | 1 | 3 | 3 | 1 | 0 | 1 | 0 | - | - | US | 0 | - | - | 0 | - | - | 2 | -5 | 0 | GB | 1 | 2 | 3 | 1 | 0 | 1 | 0 | - | - | IN | 0 | - | - | 2 | 0 | 2 | 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_iso_code
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-02290: check constraint (SQL_PEKKHYFMLUAYMNXDSCFZPTRAM.GAME_STATUS_C) violated ORA-06512: at "SYS.DBMS_SQL", line 1721More Details: https://docs.oracle.com/error-help/db/ora-02290
Add new constraint to allow new status
alter table games
add constraint game_statuses_c
check (
game_status in ( 'SCHEDULED', 'COMPLETED', 'CANCELLED', 'ABANDONED' )
)
Table altered.
Drop old constraint to allow new status
alter table games
drop constraint game_status_c
Table altered.
update games
set game_status = 'ABANDONED'
where game_id = 4
1 row(s) updated.
select /*+ gather_plan_statistics */* from games
where game_status = 'JUNK'
no data found
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) |
---|