【问题标题】:Query in Oracle to select with subquery在 Oracle 中查询以使用子查询进行选择
【发布时间】:2020-06-13 07:13:45
【问题描述】:

我的 Oracle 数据库中有下表:

CREATE TABLE test
(
 flight NUMBER(4),
 date   DATE,
 action VARCHAR2(50),
 CONSTRAINT pk PRIMARY KEY (flight,date)
);

以及以下寄存器:

BEGIN
 INSERT INTO test VALUES ('1234', '2020-02-29 18:00', 'Departure');
 INSERT INTO test VALUES ('1234', '2020-02-29 19:00', 'Arrival');

 INSERT INTO test VALUES ('4321', '2020-02-20 22:00', 'Departure');
 INSERT INTO test VALUES ('4321', '2020-02-21 04:30', 'Arrival');
END;
/

我的问题是,我想做一个 SELECT,只在航班起飞并在同一天到达时才返回我的航班号。例如,“1234”航班在第 29 天起飞,在第 29 天到达,而“4321”航班在第 20 天起飞,在第 21 天到达。我只想选择“1234”航班',因为它是唯一满足要求的人。

我一直在考虑下面的选择,但它不起作用,因为子查询返回的值不止一个:

SELECT flight
  FROM test
 WHERE action = 'Departure'
   AND TO_CHAR(date, 'YYYY-MM-DD') = (SELECT TO_CHAR(date, 'YYYY-MM-DD')
                                        FROM test
                                       WHERE action = 'Arrival');

非常感谢。

【问题讨论】:

  • 重复使用航班号是很常见的。您的数据模型中是否也会发生两个不同的航班具有相同的航班号或航班号唯一标识您表中的航班的情况?
  • 顺便说一句,您不需要像您的情况那样在日期之间进行to_char() 转换。如果 date 列上存在索引,那么这种转换就会消除索引的影响。

标签: sql oracle date select constraints


【解决方案1】:

PIVOT 语句也可以工作

SELECT *
FROM (SELECT flight, date, action
    FROM test)

PIVOT
    (
      MAX(DATE)
      FOR ACTION IN ('Departure' AS DEP, 'Arrival' AS AR)
    )WHERE TRUNC(DEP) = TRUNC(AR)

【讨论】:

    【解决方案2】:

    我们不知道您的数据模型中的航班号是否唯一代表一个航班。我们也不知道除了“Departure”和“Arrival”是否还有其他动作。

    以下解决方案会结合航班日期查看航班号,并考虑有问题的两个操作,因此它们在任何情况下都有效:

    INTERSECT:

    select flight, trunc(date) from test where action = 'Departure'
    intersect
    select flight, trunc(date) from test where action = 'Arrival';
    

    带聚合:

    select flight, trunc(date)
    from test
    group by flight, trunc(date)
    having count(case when action = 'Departure' then 1 end) = 1
       and count(case when action = 'Arrival' then 1 end) = 1;
    

    【讨论】:

      【解决方案3】:

      你需要两次加入同一张表

      SELECT t1.flight
      FROM test t1
      INNER JOIN test t2 ON t1.action = 'Departure'
          AND TO_CHAR(t1.date, 'YYYY-MM-DD')  = TO_CHAR(t2.date, 'YYYY-MM-DD')
          AND t2.action = 'Arrival'
          AND t1.flight =t2.flight
      

      或者使用子查询..再次使用适当的 FROM 子句

      SELECT flight
      FROM test
      WHERE action = 'Departure'
      AND (TO_CHAR(date, 'YYYY-MM-DD'), flight)  = (
          SELECT TO_CHAR(date, 'YYYY-MM-DD'), flight
          FROM test
          WHERE action = 'Arrival');        
      

      【讨论】:

      • 但最后一次选择不起作用,因为子查询将返回所有航班到达的所有日期。
      • yes ..但是 with main 查询 where 条件应该只返回匹配的行 .. 别名 fligth 其中出发和到达有相同的时间。 .. 在您的查询中,您使用结果形式查询来匹配 where 条件 ..... 更好地检查,因为这两个查询返回相同的结果
      • 假设 2 只苍蝇有相同的日期。它不起作用,因为您只比较日期,主键是航班 + 日期
      【解决方案4】:

      另一种选择是使用join 与航班号和日期如下:

      SELECT distinct d.flight
        FROM test d JOIN test a 
          ON d.action = 'Departure'
          AND trunc(d.date) = trunc(a.date)
          AND a.action = 'Arrival'
          AND a.flight = d.flight;
      

      干杯!!

      【讨论】:

        【解决方案5】:

        您只需要在一天内采取不同的行动。因此,请使用 HAVING count 来区分按航班和日期分组的两个单独操作:

        SELECT flight
          FROM test
         WHERE action in ('Departure','Arrival')
         GROUP BY flight, trunc("date")
        HAVING COUNT(distinct action)=2
        

        哪里应该有distinct子句,如果样本数据集被扩展,需要观察

        Demo

        • date 是保留关键字,不能用作 Oracle 数据库的列名。所以,我更喜欢"date"
        • 在时间文字前加上 timestamp 关键字,并在末尾添加部分 :00 以表示 second,例如插入期间的 timestamp'2020-02-21 04:30:00'

        【讨论】:

          【解决方案6】:

          带有COUNT()窗口功能:

          select distinct flight
          from (
            select t.*, 
              count(distinct action) over (partition by flight, to_char("date", 'YYYY-MM-DD')) counter
            from test t
          )
          where counter = 2
          

          请参阅demo
          结果:

          > | FLIGHT |
          > | -----: |
          > |   1234 |
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-24
            • 2021-03-26
            • 2016-10-08
            • 2015-11-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多