在子查询和别名中排序

Posted

技术标签:

【中文标题】在子查询和别名中排序【英文标题】:Order by in subquery and alias 【发布时间】:2019-09-25 08:11:31 【问题描述】:

我在 oracle 查询中的 order by 有问题。

select KEY, B, C, (select D from TABLE1 a where a.KEY = b.KEY and a.DATE< 
b.DATE order BY a.DATE and rownum =1 ) 
FROMSTATUS from TABLE2 b

我知道“order by”在子查询中不起作用。我将查询修改为:

select KEY, B, C, (select * from (select D from TABLE1 a where a.KEY = 
b.KEY and a.DATE< b.DATE order by DATE) where rownum = 1)
FROMSTATUS from TABLE2 b

但是通过这种方式 B.KEY 和 B.DATE 并没有被 oracle 解析

我只需要从 TABLE2 中选择一个 1 值,该值是前一个 a.DATE

例子:

 TABLE1
 KEY    DATE        A    B    C 
 1      01/31/2000  1    2    3
 2      02/25/2000  X    Y    Z   

 TABLE2
 KEY    DATE          D
 1      01/30/2000    1
 1      01/27/2000    2
 1      01/25/2000    2
 2      02/20/2000    4
 2      02/13/2000    1

我需要这个结果:

TABLE1.KEY   TABLE1.DATE    TABLE1.A TABLE1.B TABLE1.C TABLE2.DATE TABLE2.D
1            01/31/2000     1        2        3        01/30/2000  1
2            02/25/2000     X        Y        Z        02/20/2000  4

你能帮帮我吗?

(对不起我的英语不好)

【问题讨论】:

跳过子查询,改为执行 LEFT JOIN。 查询与您的描述不符。您已将 table1 和 table2 混合在一起。您还应用了错误的顺序,它必须是 order by date desc 才能首先获得最高日期。 @ThorstenKettner 你有理由,我有正确的问题 【参考方案1】:

union 之后的row_number() 会得到你的输出。

 select tFinal.DATE, tFinal.KEY 
 from (select row_number() over (partition by KEY order by t1.T, t1.DATE desc) as rn, t1.DATE, t1.KEY 
        from 
        (select DATE, KEY, 't1' as T from TABLE1
        union all
        select DATE, KEY, 't2' as T from TABLE2) t1) tFinal
 Where rn = 2

【讨论】:

【参考方案2】:

您可以为此使用窗口函数:

WITH cte AS (
    SELECT TABLE2.KEY, TABLE2.B, TABLE2.C, TABLE1.D
         , ROW_NUMBER() OVER (PARTITION BY TABLE2.KEY, TABLE2.DATE ORDER BY TABLE1.DATE DESC) AS rn
    FROM TABLE2
    LEFT JOIN TABLE1 ON TABLE2.KEY = TABLE1.KEY AND TABLE2.DATE > TABLE1.DATE
)
SELECT *
FROM cte
WHERE rn = 1

【讨论】:

【参考方案3】:

这是一个使用聚合的答案:

WITH t1 AS (SELECT 1 KEY, to_date('31/01/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
            SELECT 2 KEY, to_date('25/02/2000', 'dd/mm/yyyy') dt FROM dual),
     t2 AS (SELECT 1 KEY, to_date('30/01/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
            SELECT 1 KEY, to_date('27/01/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
            SELECT 1 KEY, to_date('25/01/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
            SELECT 2 KEY, to_date('20/02/2000', 'dd/mm/yyyy') dt FROM dual UNION ALL
            SELECT 2 KEY, to_date('13/02/2000', 'dd/mm/yyyy') dt FROM dual)
SELECT t1.KEY,
       t1.dt t1_date,
       MAX(t2.dt) t2_date
FROM   t1
       LEFT OUTER JOIN t2 ON t1.key = t2.key AND t2.dt < t1.dt
GROUP BY t1.key, t1.dt
ORDER BY t1.key;

       KEY T1_DATE     T2_DATE
---------- ----------- -----------
         1 31/01/2000  30/01/2000
         2 25/02/2000  20/02/2000

我在这里假设 t1.key 是一个唯一的列。这是否比您的数据的任何其他答案更具性能取决于您来测试 *:-)

【讨论】:

【参考方案4】:

在 Oracle 中,您可以为此使用 KEEP LAST

select
  key,
  b,
  c,
  (
    select max(d) keep (dense_rank last order by t2.date)
    from table2 t2
    where t2.key = t1.key and t2.date < t1.date
  ) as fromstatus
from table1 t1;

从 Oracle 12c 开始,您还可以使用 FETCH FIRST ROW

select
  key,
  b,
  c,
  (
    select d
    from table2 t2
    where t2.key = t1.key and t2.date < t1.date
    order by t2.date desc
    fetch first row only
  ) as fromstatus
from table1 t1;

或者,将子查询移动到FROM 子句:

select
  t1.key,
  t1.b,
  t1.c,
  first_t2.d as fromstatus
from table1 t1
outer apply
(
  select d
  from table2 t2
  where t2.key = t1.key and t2.date < t1.date
  order by t2.date desc
  fetch first row only
) first_t2;

最后一个查询的优点是您可以轻松地从 table2 行中选择更多值,而不仅仅是一个。

【讨论】:

以上是关于在子查询和别名中排序的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server - 在子查询中使用列别名

在子查询中排序

Sqlite:在子查询“消除”结果中排序

Oracle 分页查询在子查询中使用了 排序和like 会影响效率吗? 怎样优化呢

oracle 如何查询指定记录行数的记录

在 T-SQL 中,如何在子查询中引用表变量?