【问题标题】:SQL Query - Queries involving AVG of COUNT and queries involving datesSQL 查询 - 涉及 COUNT 的 AVG 的查询和涉及日期的查询
【发布时间】:2016-07-26 03:23:04
【问题描述】:

我的数据库如下所示:

峰(姓名、海拔高度、差值、地图、地区)
登山者(姓名、性别)
参加(TRIP_ID、姓名)
爬升(TRIP_ID、PEAK、WHEN)

  • PEAK 提供有关用户感兴趣的山峰的信息。该表列出了每个山峰的名称、海拔(以英尺为单位)、难度级别(1-5 级)、地图位于及其所在的内华达山脉地区。
  • CLIMBER 列出了俱乐部的成员,并给出了他们的姓名和性别。
  • PARTICIPATED 提供了参加过各种登山旅行的登山者的集合。每次旅行的参与者人数各不相同。
  • CLIMBED 会根据每座山峰的攀登数据,告诉您每次攀登过程中攀登了哪些山峰。

我需要为这 2 个示例场景编写 SQL 查询的帮助:

  • 计算俱乐部中男性和俱乐部中女性的平均峰数。
  • 玛丽亚攀登过的每一座山峰都有哪些人攀登?
  • 谁在大约 60 天内攀登了 20 多座山峰?

编辑:第一个查询现在可以工作,看起来像这样:

SELECT SEX, AVG(num_peaks) AS avg_peaks
FROM 
   (
    SELECT CLIMBER.*, COUNT(CLIMBED.PEAK) num_peaks
    FROM CLIMBED
    INNER JOIN PARTICIPATED
    ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID
    RIGHT OUTER JOIN CLIMBER
    ON CLIMBER.NAME = PARTICIPATED.NAME
    GROUP BY CLIMBER.NAME, CLIMBER.SEX
  )
GROUP BY SEX; 

此查询为我提供了男性和女性攀登的山峰总数。但我似乎无法弄清楚如何获得平均值而不是计数。我知道你不能简单地将 COUNT 函数更改为 AVG b/c 我的数据是字符串形式而不是整数。

我的第二个查询如下所示:

SELECT DISTINCT PARTICIPATED.NAME
FROM PARTICIPATED
INNER JOIN CLIMBED
ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID
WHERE CLIMBED.PEAK IN
    (
     SELECT CLIMBED.PEAK
     FROM CLIMBED
     INNER JOIN PARTICIPATED
     ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID
     WHERE NAME IN ('MARIA')
    )
AND PARTICIPATED.NAME NOT IN ('MARIA');

该查询为我提供了所有攀登过 Maria 也攀登过的山峰的人,但并没有只提供已经攀登过 Maria 已经攀登的每一个单峰的人。不知道如何以这种方式过滤掉其余的人。

最后我的最终查询如下所示:

SELECT PARTICIPATED.NAME, COUNT(DISTINCT CLIMBED.PEAK)
FROM PARTICIPATED
LEFT JOIN CLIMBED
ON CLIMBED.TRIP_ID = PARTICIPATED.TRIP_ID
GROUP BY PARTICIPATED.NAME;

这个查询给出了所有登山者的名字和他们每个人攀登过的山峰总数,但我不知道如何进一步过滤它,以便它只显示在 60 内攀登过 20 多座山峰的人天跨度。 我尝试使用

HAVING CLIMBED.WHEN BETWEEN -60 AND 60;

但这不起作用。

非常感谢任何帮助,我正在使用 Oracle Express 作为我的数据库。

【问题讨论】:

  • 你已经发布了这个问题here
  • 不是对您的整个问题的回应。但是您的第二个查询应该有WHERE CLIMBED.PEAK = ALL (... WHERE NAME = 'MARIA') AND NAME <> 'MARIA'。使用IN 等价于= ANY(...),但您需要所有的峰,而不仅仅是一个。此外,将 IN 用于单个值是没有意义的,请改用 = 和 。你有一个额外的分号。见this post about ORACLE and ANY, ALL, and SOME

标签: sql oracle date count oracle-xe


【解决方案1】:

我确实是在SQL server上工作,所以我在网上搜索了oracle语法,可能有一些错误,但我认为没问题。

关于您的第一个查询,我的想法是做一个子查询,计算每个参与者攀登的山峰数量,然后取每个性别的平均值。我使用with 语法尽可能清晰地分隔子查询。

WITH TABLE_COUNT AS
( SELECT COUNT(CLIMBED.PEAK) AS NUMBER_CLIMBED,
CLIMBER.SEX,
CLIMBER.NAME
FROM CLIMBED
INNER JOIN PARTICIPATED
ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID
INNER JOIN CLIMBER
ON CLIMBER.NAME = PARTICIPATED.NAME
GROUP BY CLIMBER.SEX, CLIMBER.NAME;
)
SELECT AVG(NUMBER_CLIMBED),
SEX
FROM TABLE_COUNT
GROUP BY SEX

那么,关于你的第二个问题,我会换一种方式。我会为每个登山者准备一张桌子,并为玛丽亚攀爬过的每个坑划一条线。如果 Maria 爬过的坑没有被登山者爬过,那么一列的值将是 1,否则为 0。如果总和为零,则登山者攀登了玛丽亚攀登的所有山峰。

让我们首先选择玛丽亚爬过的每个坑,在另一个表中选择其他人爬过的每个山峰,然后使用LEFT JOIN 加入他们;我不知道你是否知道它是如何工作的,但如果没有攀登高峰,它会给出NULL 值,这正是我们所寻找的。它只会给出玛丽亚攀登的山峰,而不是其他山峰。我在TABLE_PARTICIPER 中使用 group by 以避免行数过多,但这不是必需的。

WITH TABLE_MARIA AS 
(
 SELECT CLIMBED.PEAK
 FROM CLIMBED
 INNER JOIN PARTICIPATED
 ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID
 WHERE NAME IN ('MARIA')
),

 TABLE_PARTICIPER AS 
( 
 SELECT CLIMBED.PEAK,
 NAME
 FROM CLIMBED
 INNER JOIN PARTICIPATED
 ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID
 WHERE NAME NOT IN ('MARIA')
 GROUP BY NAME,
 CLIMBED.PEAK
)

现在我将使用 Maria 攀登的每个山峰、其他参与者的每个姓名以及他们攀登的山峰、NULL 如果他们没有攀登,然后使用 having 函数选择它们。

SELECT NAME
FROM (
SELECT TABLE_MARIA.PEAK AS MARIA_PEAK,
TABLE_PARTICIPER.PEAK AS PARTICIPER_PEAK,
TABLE_PARTICIPER.NAME
FROM TABLE_MARIA
LEFT JOIN TABLE_PARTICIPER ON TABLE_MARIA.PEAK = TABLE_PARTICIPER.PEAK
) AS QUERY
GROUP BY NAME HAVING SUM(CASE WHEN PARTICIPER_PEAK IS NULL THEN 1 ELSE 0 END) = 0

这应该可以完美运行。如果有问题请告诉我。

关于最后一个查询,我们可以做一些“脏”的事情。让我们为每个登山者、他们在每个日期攀登的每个山峰建一个表格,然后将其与自身连接起来,为每个登山者在每个日期有很多行,以了解他在该日期之前的 60 天内攀登了多少座山峰.然后我们可以计算每个登山者的数量并确定行数,并且只选择计数为 20 的登山者。

WITH TABLE_PEAKS AS 
(
SELECT CLIMBED.PEAK,
 CLIMBED.WHEN,
 PARTICIPATED.NAME
 FROM CLIMBED
 INNER JOIN PARTICIPATED
 ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID
)

SELECT DISTINCT NAME
FROM (
SELECT T1.NAME
FROM TABLE_PEAKS T1
LEFT JOIN TABLE_PEAKS T2 ON T1.NAME = T2.NAME AND 
(T2.WHEN > T1.WHEN OR (T2.WHEN=T1.WHEN AND T2.PEAK <>T1.PEAK)) 
AND NOT (T2.WHEN > ADDDATE(T1.WHEN,60))
) AS QUERY
GROUP BY NAME
HAVING COUNT(*) > 20

如果有问题请告诉我!

【讨论】:

  • 我已经弄清楚了第一个问题,但第二个问题我不知道如何将您的答案拼凑在一起以获得有效的查询。
  • 哎呀,对不起,我忘记了两个带子句之间的逗号,我的答案已被编辑。对不起!
  • 我想问你的第三个问题,你是指在60天内攀登了20个不同山峰的人,还是即使有3次同一个山峰也能攀登20个山峰的人?是 60 天还是 120 天(给定日期之前或之后 60 天)?
  • 总共 20 个峰值,相同的峰值很好。我认为 120 天是(给定日期之前或之后的 60 天),只要被查询的人在任何 60 天内攀登 20 座山峰。
  • 对于第一个查询,我在第 9 行遇到无效表名错误: WITH table_participer AS
猜你喜欢
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
  • 1970-01-01
  • 2016-07-24
  • 1970-01-01
  • 2023-02-21
相关资源
最近更新 更多