SQL查询,平均攀升以及攀升最多峰值的对

时间:2016-04-05 21:46:26

标签: sql oracle

我的数据库看起来像这样:

  • PEAK(姓名,ELEV,DIFF,MAP,REGION)
  • CLIMBER(NAME,SEX)
  • 参与(TRIP_ID,NAME)
  • CLIMBED(TRIP_ID,PEAK,WHEN)

PEAK提供有关用户感兴趣的山峰的信息。该表列出了每个峰的名称,高程(以英尺为单位),其难度级别(以1-5为单位),其中的地图位于内华达山脉及其所在地区。

CLIMBER列出了俱乐部的成员,并列出了他们的姓名和性别。

PARTICIPATED为参加各种攀岩之旅的登山者提供了一套。每次旅行的参与者人数各不相同。

CLIMBED告诉我们每次登山旅行时攀爬的峰值,以及每个峰值爬升的数据。

我需要帮助编写以下内容的查询:

  1. 计算俱乐部中男性和俱乐部中女性的平均峰值数。
  2. 哪一对攀登者攀登了最多的山峰,那是多少峰?
  3. 谁在60天内爬了20多个山峰?
  4. 对于第一个查询,到目前为止,我已经找到了一种方法来计算男性所攀升的峰值总数:

    SELECT SUM(C)
    FROM 
      (SELECT CD.PEAK, COUNT(*) C
      FROM CLIMBED CD
      WHERE CD.TRIP_ID IN
        (SELECT TRIP_ID
        FROM PARTICIPATED PA
        WHERE PA.NAME IN 
          (SELECT NAME
          FROM CLIMBER
          WHERE SEX = 'M'))
      GROUP BY CD.PEAK) T;
    

    对于第二个查询,我有以下内容,我相当肯定是不正确的:

    SELECT TEMP2.TRIP_ID, COUNT (*)
    FROM
      (SELECT P1.NAME, P2.NAME, P1.TRIP_ID
      FROM PARTICIPATED P1, PARTICIPATED P2
      WHERE P1.NAME <> P2.NAME AND
            P1.TRIP_ID = P2.TRIP_ID) TEMP1,
      (SELECT *
      FROM CLIMBED) TEMP2
    WHERE TEMP2.TRIP_ID = TEMP1.TRIP_ID
    GROUP BY TEMP2.TRIP_ID;
    

3 个答案:

答案 0 :(得分:0)

问题1: 总行程次数(包括每次攀登高峰时)

SELECT t1.sex, AVG(t1.peak_count) AS average
FROM
    (SELECT sex, COUNT(trip_id) AS peak_count
     FROM climber c LEFT JOIN  participated p ON c.name = p.name GROUP BY c.name, c.sex) t1

每次爬上一个独特的高峰时:

SELECT t1.sex, AVG(t1.peak_count) AS average
FROM
    (SELECT sex, COUNT(trip_id) AS peak_count
     FROM climber c LEFT JOIN  participated p ON c.name = p.name GROUP BY c.name, c.sex) t1

问题2:

SELECT P1.Name, P2.Name, COUNT(DISTINCT p1.trip_id) AS trips
FROM participated p1 INNER JOIN  participated p2 ON p1.trip_id = p2.trip_id
WHERE p1.name > p2.name -- > instead of <> gets only one of the pairs
GROUP BY P1.Name, P2.Name 
HAVING COUNT(DISTINCT p1.trip_id) > 0
ORDER BY trips DESC

问题3:

SELECT p.name, cl.when AS span_begin_date, DATEADD(day, 60, cl.when) AS span_end_date, count(c2.trip_id) AS peaks
FROM climbed cl LEFT JOIN 
climbed c2 ON c2.when BETWEEN cl.when AND DATEADD(day, 60, cl.when)
GROUP BY p.name, cl.when, DATEADD(day, 60, cl.when)
HAVING COUNT(c2.trip_id) > 20
ORDER BY peaks

答案 1 :(得分:0)

这是我的解决方案。如果您提供样本数据,则可以验证。对于问题3,大约60天的时间跨度尚不清楚。你能指点一下吗?

问题1

select x.sex, avg(x.peaks_escalated) as peaks
from (
    select u.name, u.sex, count(distinct c.peak) as peaks_escalated
    from t1_climbed c 
         inner join t1_participated p on c.trip_id = p.trip_id 
         inner join t1_climber u on p.name = u.name
    group by u.name, u.sex ) x
group by x.sex

问题2

with list1 as (
select u.name as member, c.trip_id, c.peak, c.when
from t1_climbed c 
     inner join t1_participated p on c.trip_id = p.trip_id 
     inner join t1_climber u on p.name = u.name
)
select a.member as m1, b.member as m2, count(distinct a.peak) as total
from list1 a inner join list1 b 
            on a.trip_id = b.trip_id 
            and a.peak = b.peak 
            and a.when = b.when 
            and a.member <> b.member
group by a.member, b.member

答案 2 :(得分:0)

Oracle安装程序

CREATE TABLE PEAK (
  NAME VARCHAR2(50) PRIMARY KEY,
  ELEV INT,
  DIFF INT,
  MAP  VARCHAR2(10),
  REGION VARCHAR2(10)
);

CREATE TABLE CLIMBER (
  NAME VARCHAR2(50) PRIMARY KEY,
  SEX  CHAR(1) CHECK ( SEX IN ( 'M', 'F' ) )
);

-- Created this to have a primary key    
CREATE TABLE TRIPS (
  TRIP_ID INT PRIMARY KEY
);

CREATE TABLE PARTICIPATED (
  TRIP_ID INT REFERENCES TRIPS( TRIP_ID ),
  NAME  VARCHAR2(50) REFERENCES CLIMBER( NAME ),
  PRIMARY KEY ( TRIP_ID, NAME )
);

CREATE TABLE CLIMBED (
  TRIP_ID INT          REFERENCES TRIPS( TRIP_ID ),
  PEAK    VARCHAR2(50) REFERENCES PEAK ( NAME ),
  "WHEN"  DATE
);

问题1

SELECT sex,
       AVG( num_peaks ) AS avg_peaks
FROM   (
  SELECT c.*,
         COUNT( DISTINCT l.peak ) num_peaks
  FROM   CLIMBED l
         INNER JOIN
         PARTICIPATED p
         ON ( p.trip_id = l.trip_id )
         RIGHT OUTER JOIN
         CLIMBER c
         ON ( p.name = c.name )
  GROUP BY c.name, c.sex
)
GROUP BY sex;

你需要OUTER JOIN登山者,因为他们可能没有参加任何旅行(因此攀登了0个峰值),这需要在平均值中加以考虑。一个人也有可能多次攀登过一个峰值 - 当你想要在同一个峰值上排除多个攀爬的人攀登的峰值数量时,需要使用COUNT( DISTINCT ... )(或其他类似物)技术) - 如果你想计算多次爬升,那么删除DISTINCT关键字。

问题2

SELECT *
FROM   (
  SELECT  name1,
          name2,
          COUNT( DISTINCT c.peak ) AS num_peaks_climbed
  FROM    (
            SELECT  p1.name AS name1,
                    p2.name AS name2,
                    p1.trip_id
            FROM    PARTICIPATED p1
                    INNER JOIN
                    PARTICIPATED p2
                    ON ( p1.trip_id = p2.trip_id AND p1.name < p2.name )
          ) p
          INNER JOIN
          climbed c
          ON ( p.trip_id = c.trip_id )
  GROUP BY name1, name2
  ORDER BY num_peaks_climbed DESC
)
WHERE ROWNUM = 1;

问题3

SELECT *
FROM   (
  SELECT p.name,
         COUNT( c.peak ) OVER ( PARTITION BY p.name
                                ORDER BY c."WHEN"
                                RANGE BETWEEN INTERVAL '-60' DAY PRECEDING
                                          AND CURRENT ROW
                              ) AS num_peaks_in_60_days,
         c."WHEN" AS last_date_of_range
  FROM   PARTICIPATED p
         INNER JOIN
         climbed c
         ON ( p.trip_id = c.trip_id )
)
WHERE  num_peaks_in_60_days > 20;