【问题标题】:SQL Query, Average climbed and pair that has climbed the most peaksSQL查询,平均攀登和攀登最多峰的配对
【发布时间】:2016-04-06 08:10:42
【问题描述】:

我的数据库如下所示:

  • 峰值(名称、海拔高度、差异、地图、地区)
  • 攀登者(姓名、性别)
  • 参与(TRIP_ID,姓名)
  • 爬升(TRIP_ID、峰值、时间)

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

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

PARTICIPATED 给出了参加过各种登山旅行的登山者的集合。每次旅行的参与者人数各不相同。

CLIMBED 会根据每座山峰的攀登数据告诉您每次攀登行程中攀登了哪些山峰。

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

  1. 计算俱乐部中男性和俱乐部中女性的平均峰数。
  2. 哪对登山者一起攀登的山峰最多,那是多少座山峰?
  3. 谁在大约 60 天内攀登了 20 多座山峰?

对于第一个查询,到目前为止,我已经找到了一种计算男性攀登高峰总数的方法:

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;

【问题讨论】:

  • 您能提供一些表格的数据吗?

标签: sql oracle


【解决方案1】:

问题 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

【讨论】:

  • 您的第一个查询考虑到一次旅行等于一次高峰,根据提供的模型,我认为这不是真的。
【解决方案2】:

这是我的解决方案。如果您提供样本数据,则可以验证这一点。对于问题 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

【讨论】:

  • 问题 1 是“计算山峰的平均数量......”但您计算的是总(不是平均)攀登次数(不是山峰 - 人们可以多次攀登山峰)。您还将排除未参加过任何旅行的人(这会人为地夸大平均值)。
【解决方案3】:

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;

【讨论】:

    猜你喜欢
    • 2020-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    相关资源
    最近更新 更多