在 Oracle 中取最大相关值?

Posted

技术标签:

【中文标题】在 Oracle 中取最大相关值?【英文标题】:Take max correlated value in Oracle? 【发布时间】:2020-07-16 16:24:08 【问题描述】:

我的 Oracle 11g 数据库中有以下表:

CREATE TABLE travels
(
Day DATE,
Flight_Code VARCHAR2(7),
Airplane_Code VARCHAR2(7),
CONSTRAINT pk PRIMARY KEY(day,flight_code)
);

CREATE TABLE boardings
(
Passport VARCHAR2(7),
Day DATE,
Flight_Code VARCHAR2(7),
Luggage_Weight NUMBER(4,2),
CONSTRAINT pk PRIMARY KEY(passport,day,flight_code)
);

所以我试图进行查询,以查看每架飞机的最大重量(Day 和 Flight_Code),该重量始终高于 100(请记住同一个航班,例如 RY-1234-VY,可以在不同的日子进行不同的旅行,但同一天不能超过一次)。

我一直在尝试这样的事情,但它不起作用,因为它返回每个航班,这是它已经运输更多 Luggage_Weight 的那一天,以及完成它的飞机。

SELECT Airplane_Code, Day, Flight_Code
FROM Travels
WHERE (Day, Flight_Code) IN (SELECT Day, Flight_Code
                                 FROM boardings b1
                                 GROUP BY Day, Flight_Code
                                 HAVING SUM(Luggage_Weight) = (SELECT MAX(SUM(Luggage_Weight))
                                                              FROM boardings b2
                                                              WHERE b1.Flight_Code = b2.Flight_Code
                                                              GROUP BY Day, Flight_Code
                                                              HAVING SUM(Luggage_Weight) > 100))
GROUP BY Airplane_Code, Day, Flight_Code;

我想要使用 GROUP BY 和 HAVING 结构的解决方案。

例如:

INSERT INTO travels VALUES ('04/04/2020', 'RY1234', 'ABCD');
INSERT INTO travels VALUES ('03/04/2020', 'RY1234', 'ABCD');

INSERT INTO boardings VALUES ('ES1234', '04/04/2020', 'RY1234', '51');
INSERT INTO boardings VALUES ('ES5678', '04/04/2020', 'RY1234', '50');
INSERT INTO boardings VALUES ('ES9101', '03/04/2020', 'RY1234', '100');

如您所见,同一个航班 (RY1234) 已在 2 个不同的日子旅行,因此在 03/04 总行李重量为 100 公斤,但在 04/04 总行李重量为 101 公斤。结果应该是下一个:

ABCD ---- 04/04/2020 ---- RY1234

如果同一架飞机的任何一次航班的重量都没有达到 100 公斤,则不应显示该飞机代码。

【问题讨论】:

Edit 问题并将示例数据添加为INSERT INTO 语句,并将所需结果添加为表格文本。 成功了!请看一下 【参考方案1】:

您可以在派生表中使用dense_rank(),按照航班的权重sum() 对航班进行排名。然后将其加入travels 并过滤排名为1

SELECT t.airplane_code,
       t.day,
       t.flight_code
       FROM travels t
            INNER JOIN (SELECT b.day,
                               b.flight_code,
                               dense_rank() OVER (ORDER BY sum(b.luggage_weight) DESC) dr
                               FROM boardings b
                               GROUP BY b.day,
                                        b.flight_code) x
                       ON x.day = t.day
                          AND x.flight_code = t.flight_code
            WHERE x.dr = 1;

db<>fiddle

【讨论】:

您能告诉我如何使用 GROUP BY 和 HAVING 吗?只是更新我的尝试并告诉我要改变什么 @Trick:查询中有GROUP BY,不是吗? 是的,我知道,但是如何只使用 GROUP BY 和 HAVING?我的意思是,不使用dense_rank()、OVER、ORDER BY...等想法。 但我需要像我说的那样 @Trick:没有限制,Oracle 可以做窗口函数。 11g也是。小提琴只有 18c,因为目前没有 11g。试试看吧。【参考方案2】:
select Airplane_Code,day,Flight_Code from (
Select Airplane_Code,day,Flight_Code ,sum(Luggage_Weight) over (Partition by 
Flight_Code,day) as total_weight
from travels t,boardings b
where t.Flight_Code=b.Flight_Code)data1
where data1.total_weight >100;

【讨论】:

如果使用代码格式会更容易查看。另外,我说我更喜欢它是 GROUP BY 和 HAVING 结构【参考方案3】:

您可以将子查询重构与 GROUP BY 和 HAVING 一起使用,如下所示。

当您说以下内容时,您需要单独按 Flight_code 分组以获得最大重量。

所以我试图进行查询,以便查看每架飞机的航班(Day 和 Flight_Code),它已经运输了最大重量,该重量始终高于 100(保持请记住,同一个航班,例如 RY-1234-VY,可以在不同的日子进行不同的旅行,但同一天不能超过一次)。

            WITH t
             AS (SELECT t.airplane_code,
                        t.day,
                        t.flight_code,
                        SUM(luggage_weight) wt
                 FROM   travels t,
                        boardings b
                 WHERE  t.flight_code = b.flight_code
                        AND Trunc(t.day) = Trunc(b.day)
                 GROUP  BY t.airplane_code,
                           t.day,
                           t.flight_code
                 HAVING SUM(luggage_weight) > 100),
             t1
             AS (SELECT Max(wt) wt,
                        flight_code
                 FROM   t
                 GROUP  BY
                           flight_code)
        SELECT t.*
        FROM   t,
               t1
        WHERE  t.wt = t1.wt
               AND t.flight_code = t1.flight_code 

没有子查询重构,你可以像下面这样使用

 SELECT t.airplane_code,
           t.day,
           t.flight_code
    FROM   travels t,
           boardings b
    WHERE  t.flight_code = b.flight_code
           AND Trunc(t.day) = Trunc(b.day)
    GROUP  BY t.airplane_code,
              t.day,
              t.flight_code
    HAVING SUM(luggage_weight) IN (SELECT Max(wt) wt
                                   FROM   (SELECT b.day,
                                                  b.flight_code,
                                                  SUM(luggage_weight) wt
                                           FROM   boardings b
                                           GROUP  BY b.day,
                                                     b.flight_code
                                           HAVING SUM(luggage_weight) > 100)rec
                                   WHERE  rec.flight_code = t.flight_code
                                   GROUP  BY t.flight_code)

你也可以使用类似下面的东西

   SELECT *
    FROM   travels t
    WHERE  ( Trunc(t.day), t.flight_code ) IN (SELECT Trunc(b.day),
                                                      b.flight_code
                                               FROM   boardings b
                                               GROUP  BY b.day,
                                                         b.flight_code
                                               HAVING SUM(luggage_weight) IN
                                                      (SELECT Max(wt) wt
                                                       FROM
                                              (SELECT b.day,
                                                      b.flight_code,
                                                      SUM(luggage_weight)
                                                      wt
                                               FROM   boardings b
                                               GROUP  BY b.day,
                                                         b.flight_code
                                               HAVING SUM(luggage_weight) >
                                                      100)rec
                                                       WHERE
                  rec.flight_code = b.flight_code

【讨论】:

不使用 WITH 会怎么样?我的意思是,结构与我展示的示例相似 更新了答案 这种情况下TRUNC的作用是什么? 如果 day 有时间值,则需要 trunc 但我不想显示行李重量的总和,只显示飞机代码、航班代码和日期。是否也需要加入登机牌?

以上是关于在 Oracle 中取最大相关值?的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle 中避免相关子查询

Oracle 优化相关

如何在 Pig 中查询与最小值/最大值相关的数据

从相关系数计算中去除异常值

Django ORM按两个相关模型的最大列值过滤

oracle——数据表的相关操作——插入数据以及批量插入数据