所以我有这个数据库:
CREATE TABLE team (
id CHAR(3),
name VARCHAR2(80) CONSTRAINT nn_team_name NOT NULL,
district VARCHAR2(20) CONSTRAINT nn_team_district NOT NULL,
CONSTRAINT pk_team
PRIMARY KEY (id)
);
CREATE TABLE game (
home,
away,
round NUMBER(2) CONSTRAINT nn_game_round NOT NULL,
spectators NUMBER(5),
--
CONSTRAINT pk_game
PRIMARY KEY (home, away),
--
CONSTRAINT fk_game_home
FOREIGN KEY (home)
REFERENCES team(id),
CONSTRAINT fk_game_away
FOREIGN KEY (away)
REFERENCES team(id),
--
CONSTRAINT ck_game_round
CHECK (round BETWEEN 1 AND 30),
CONSTRAINT ck_game_spectators
CHECK (spectators > 0)
);
CREATE TABLE player (
nickname NUMBER(8),
name VARCHAR2(80) CONSTRAINT nn_player_name NOT NULL,
yearOfBirth NUMBER(4) CONSTRAINT nn_player_yearOfBirth NOT NULL,
team CONSTRAINT nn_player_team NOT NULL,
--
CONSTRAINT pk_player
PRIMARY KEY (nickname),
--
CONSTRAINT fk_player_team
FOREIGN KEY (team)
REFERENCES team(id),
--
CONSTRAINT ck_player_yearOfBirth
CHECK (yearOfBirth BETWEEN 1950 AND 2000)
);
CREATE TABLE plays (
player,
home,
away,
goals NUMBER(2) CONSTRAINT nn_plays_goals NOT NULL,
--
CONSTRAINT pk_plays
PRIMARY KEY (player, home, away),
--
CONSTRAINT fk_plays_player
FOREIGN KEY (player) REFERENCES player(nickname),
CONSTRAINT fk_plays_game
FOREIGN KEY (home, away) REFERENCES game(home, away),
--
CONSTRAINT ck_plays_goals
CHECK (goals >= 0)
);
和这个测试数据:
INSERT INTO TEAM (ID, NAME, DISTRICT) VALUES ('MAN','MANCHESTER UNITED','MANCHESTER');
INSERT INTO TEAM (ID,NAME,DISTRICT) VALUES ('CHE','CHELSEA FC','LONDON');
INSERT INTO PLAYER (NICKNAME,NAME,YEAROFBIRTH,TEAM) VALUES('1','VAN PERSIE','1994','MAN');
INSERT INTO PLAYER (NICKNAME,NAME,YEAROFBIRTH,TEAM) VALUES('2','TERRY','1970','CHE');
INSERT INTO GAME(HOME,AWAY,ROUND,SPECTATORS) VALUES ('MAN','CHE','1','15000');
INSERT INTO GAME(HOME,AWAY,ROUND,SPECTATORS) VALUES ('CHE','MAN','2','30000');
INSERT INTO PLAYS(PLAYER,HOME,AWAY,GOALS) VALUES('1','MAN','CHE','2');
INSERT INTO PLAYS(PLAYER,HOME,AWAY,GOALS) VALUES('2','MAN','CHE','1');
INSERT INTO PLAYS(PLAYER,HOME,AWAY,GOALS) VALUES('1','CHE','MAN','1');
并且查询:
-> Average number of goals by round for the players who were born after 1993 and never played at home.
SELECT AVG( y.goals ),
g.round
FROM player p
INNER JOIN
plays y
ON ( p.nickname = y.player AND p.team = y.home )
INNER JOIN
game g
ON ( y.home = g.home AND y.away = g.away )
WHERE NOT EXISTS ( SELECT 1
FROM plays l
WHERE p.nickname = l.player
AND p.team = l.home )
AND p.yearOfBirth > 1993
GROUP BY g.round
ORDER BY g.round;
-> Average number of goals per game per round.
The result should be ordered by round number.
WITH num_games AS (
SELECT COUNT(1) AS num_games,
round
FROM game
GROUP BY round
)
SELECT g.round,
SUM( p.goals / n.num_games )
AS avg_goals_per_game_per_round
FROM game g
INNER JOIN
plays p
ON ( g.home = p.home AND g.away = p.away )
INNER JOIN
num_games n
ON ( g.round = n.round )
GROUP BY g.round
ORDER BY g.round;
-- id's of the teams with the larger number of goals against per round.
-- In case there's more than one team with the larger number
-- of goals against, both teams should show in the result.
-- Assume the teams play in every round.
WITH player_home_or_away_goals AS (
SELECT player,
home,
away,
goals,
CASE WHEN home = (SELECT team
FROM player p
WHERE p.nickname = l.player)
THEN 'H'
ELSE 'A'
END AS home_away
FROM plays l
),
game_home_or_away_goals AS (
SELECT home,
away,
SUM( DECODE( home_away, 'H', goals, null ) ) AS home_goals,
SUM( DECODE( home_away, 'A', goals, null ) ) AS away_goals
FROM player_home_or_away_goals
GROUP BY home, away
),
team_goals_per_game_per_round AS (
SELECT g.home AS team_id,
h.home_goals AS goals_for,
h.away_goals AS goals_against,
g.round
FROM game g
INNER JOIN
game_home_or_away_goals h
ON ( g.home = h.home AND g.away = h.away )
UNION ALL
SELECT g.away AS team_id,
h.away_goals AS goals_for,
h.home_goals AS goals_against,
g.round
FROM game g
INNER JOIN
game_home_or_away_goals h
ON ( g.home = h.home AND g.away = h.away )
),
total_team_goals_per_round AS (
SELECT team_id,
round,
SUM( goals_for ) AS total_goals_for_per_round,
SUM( goals_against ) AS total_goals_against_per_round
FROM team_goals_per_game_per_round
GROUP BY team_id,
round
),
max_goals_against_per_round AS (
SELECT round,
MAX( total_goals_against_per_round ) AS greatest_goals_against
FROM total_team_goals_per_round
GROUP BY round
)
SELECT t.team_id,
t.round
FROM total_team_goals_per_round t
INNER JOIN
max_goals_against_per_round m
ON ( t.round = m.round
AND t.total_goals_against_per_round = m.greatest_goals_against );
我想用一个选择语句来做所有这些,我该怎么做?
答案 0 :(得分:0)
一条评论 - 第一个查询从样本数据中返回空结果集。
这些查询有一个共同的列 - round
我们可以使用FULL OUTER JOIN
将其加入此列。
有一点问题,因为每个查询都可以返回不同轮次,所以我们必须首先从所有查询中收集所有数字,然后加入到这个结果集,像这样(伪代码):
SELECT * FROM (
SELECT round FROM query1
UNION
SELECT round FROM query2
UNION
SELECT round FROM query3
) r
FULL OUTER JOIN query1 q1 ON r.round = q1.round
FULL OUTER JOIN query2 q2 ON r.round = q2.round
FULL OUTER JOIN query3 q1 ON r.round = q3.round
最后的查询是....以下怪物:
WITH query1 AS(
SELECT AVG( y.goals ),
g.round
FROM player p
INNER JOIN
plays y
ON ( p.nickname = y.player AND p.team = y.home )
INNER JOIN
game g
ON ( y.home = g.home AND y.away = g.away )
WHERE NOT EXISTS ( SELECT 1
FROM plays l
WHERE p.nickname = l.player
AND p.team = l.home )
AND p.yearOfBirth > 1993
GROUP BY g.round
ORDER BY g.round
),
num_games AS (
SELECT COUNT(1) AS num_games,
round
FROM game
GROUP BY round
),
query2 AS(
SELECT g.round,
SUM( p.goals / n.num_games )
AS avg_goals_per_game_per_round
FROM game g
INNER JOIN
plays p
ON ( g.home = p.home AND g.away = p.away )
INNER JOIN
num_games n
ON ( g.round = n.round )
GROUP BY g.round
ORDER BY g.round
),
player_home_or_away_goals AS (
SELECT player,
home,
away,
goals,
CASE WHEN home = (SELECT team
FROM player p
WHERE p.nickname = l.player)
THEN 'H'
ELSE 'A'
END AS home_away
FROM plays l
),
game_home_or_away_goals AS (
SELECT home,
away,
SUM( DECODE( home_away, 'H', goals, null ) ) AS home_goals,
SUM( DECODE( home_away, 'A', goals, null ) ) AS away_goals
FROM player_home_or_away_goals
GROUP BY home, away
),
team_goals_per_game_per_round AS (
SELECT g.home AS team_id,
h.home_goals AS goals_for,
h.away_goals AS goals_against,
g.round
FROM game g
INNER JOIN
game_home_or_away_goals h
ON ( g.home = h.home AND g.away = h.away )
UNION ALL
SELECT g.away AS team_id,
h.away_goals AS goals_for,
h.home_goals AS goals_against,
g.round
FROM game g
INNER JOIN
game_home_or_away_goals h
ON ( g.home = h.home AND g.away = h.away )
),
total_team_goals_per_round AS (
SELECT team_id,
round,
SUM( goals_for ) AS total_goals_for_per_round,
SUM( goals_against ) AS total_goals_against_per_round
FROM team_goals_per_game_per_round
GROUP BY team_id,
round
),
max_goals_against_per_round AS (
SELECT round,
MAX( total_goals_against_per_round ) AS greatest_goals_against
FROM total_team_goals_per_round
GROUP BY round
),
query3 AS(
SELECT t.team_id,
t.round
FROM total_team_goals_per_round t
INNER JOIN
max_goals_against_per_round m
ON ( t.round = m.round
AND t.total_goals_against_per_round = m.greatest_goals_against )
),
all_rounds AS (
SELECT round FROM query1
UNION
SELECT round FROM query2
UNION
SELECT round FROM query3
)
SELECT *
FROM all_rounds r
FULL OUTER JOIN query1 q1 ON r.round = q1.round
FULL OUTER JOIN query2 q2 ON r.round = q2.round
FULL OUTER JOIN query3 q3 ON r.round = q3.round
此查询提供以下结果(来自样本数据)
ROUND AVG(Y.GOALS) ROUND ROUND AVG_GOALS_PER_GAME_PER_ROUND TEAM_ID ROUND
---------- ------------ ---------- ---------- ---------------------------- ------- ----------
1 1 3 CHE 1
2 2 1 CHE 2