使用一个select语句进行查询

时间:2013-12-11 17:06:30

标签: sql oracle

所以我有这个数据库:

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 );

我想用一个选择语句来做所有这些,我该怎么做?

1 个答案:

答案 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