SQL查询 - 涉及COUNT的AVG和涉及日期的查询的查询

时间:2016-04-05 23:46:29

标签: sql oracle date count oracle-xe

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

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

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

我需要帮助w /为这两个示例场景编写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');

查询给了我所有攀登过玛丽亚攀登高峰的人,但并没有给我那些已经攀登每个单峰的人,玛丽亚攀登过。不知道如何以这种方式过滤掉其他人。

最后我的最终查询如下:

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

这个查询给出了所有登山者的名字以及他们每次登山时的峰值总数,但我不知道如何过滤它们,以便它只显示那些已经攀登20多个峰值的人一天的跨度。 我尝试使用

HAVING CLIMBED.WHEN BETWEEN -60 AND 60;

但这不起作用。

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

1 个答案:

答案 0 :(得分:0)

我确切地说我在SQL服务器上工作,所以我在互联网上搜索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

然后,关于你的第二个问题,我会以另一种方式思考。每个登山者都有一张桌子,玛丽亚攀爬的每个坑都有一条线。如果登山者没有爬过玛丽亚攀登的坑,那么一列将以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
)

现在我将逐步查询玛丽亚攀登的每一个峰,每个其他参与者的名字以及攀爬时的峰值,NULL如果他们没有,然后选择具有函数的那个​​。< / p>

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

告诉我你是否有问题!