【问题标题】:Oracle Efficiently joining tables with subquery in FROMOracle 在 FROM 中有效地使用子查询连接表
【发布时间】:2018-01-02 16:16:46
【问题描述】:

表 1:

| account_no | **other columns**...
+------------+-----------------------
| 1          |
| 2          |
| 3          |
| 4          |

表 2:

| account_no | TX_No | Balance | History    |
+------------+-------+---------+------------+
| 1          | 123   |  123    | 12.01.2011 |
| 1          | 234   |  2312   | 01.03.2011 |
| 3          | 232   |  212    | 19.02.2011 |
| 4          | 117   |  234    | 24.01.2011 |

我有多个连接查询,查询中的一个表(表 2)是有问题的,因为它是一个计算许多其他事物的视图,这就是为什么对该表的每个查询都是昂贵的。从表 2 中,对于表 1 中的每个 account_no,我需要具有最大 TX_NO 的整行,这就是我的做法:

SELECT * FROM TABLE1 A LEFT JOIN 
            ( SELECT 
                    X.ACCOUNT_NO, 
                    HISTORY, 
                    X.BALANCE 
              FROM TABLE2 X INNER JOIN 
                (SELECT 
                        ACCOUNT_NO, 
                        MAX(TX_NO) AS TX_NO 
                FROM TABLE2 
                GROUP BY ACCOUNT_NO) Y ON X.ACCOUNT_NO = Y.ACCOUNT_NO) B 
            ON B.ACCOUNT_NO = A.ACCOUNT_NO

据我了解,它会对 Table2 中的所有行进行内连接,然后左连接需要account_noTable1 一起使用,这就是我想避免。

我的问题:有没有办法只为 Table1 中的那些帐户找到max(TX_NO) 而不是全部查找?我认为这将有助于提高查询速度。

【问题讨论】:

    标签: sql oracle join oracle10g


    【解决方案1】:

    我认为您走在正确的轨道上,但我认为您不需要也不会像您所做的那样嵌套子查询。相反,如果您想从表 1 中获取每条记录并从表 2 中获取匹配的最大记录,您可以尝试以下操作:

    SELECT * FROM TABLE1 t1
    LEFT JOIN
    (
        SELECT t.*,
            ROW_NUMBER() OVER (PARTITION BY account_no ORDER BY TX_No DESC) rn
        FROM TABLE2 t
    ) t2
        ON t1.account_no = t2.account_no AND
           t2.rn = 1
    

    如果你想继续你原来的方法,我会这样做:

    SELECT *
    FROM TABLE1 t1
    LEFT JOIN TABLE2 t2
        ON t1.account_no = t2.account_no
    INNER JOIN
    (
        SELECT account_no, MAX(TX_No) AS max_tx_no
        FROM TABLE2
        GROUP BY account_no
    ) t3
        ON t2.account_no = t3.account_no AND
           t2.TX_No      = t3.max_tx_no
    

    我们没有使用窗口函数来查找TABLE2 中每个帐户的最大记录,而是使用子查询的第二个连接。我希望窗口函数方法比这种双连接方法执行得更好,并且一旦你习惯了它会更容易阅读。

    【讨论】:

    • 呃,是的,这看起来是个好主意,应该考虑窗口功能,我会尝试
    • 是的,它把时间减少了一半,我觉得这很棒。唯一的事情是,通过像在您的查询中那样执行该窗口功能,我得到ORA-30483: window functions are not allowed here 错误。这就是为什么我首先使用 ROW_NUMBER().. as rn 作为子查询从另一个选择中进行选择,然后使用标准 where rn = 1
    • @Hatik 是的,你是对的,我更新了我的答案。我没有太多示例数据,而且很难在 SQLFiddle 和 Rextester 上测试 Oracle。
    • 另一件事是,我认为有必要为TABLE2 添加别名FROM TABLE2 b 并在选择使用select b.*, rownumber... ps 不要误解我,我只是希望答案是完成
    【解决方案2】:

    如果 table1 相对便宜,那么您可以考虑先进行左外连接,这将大大减少结果集,并从中单独选择最新的事务 id 记录

    select <required columns> from 
     (
     select f.<required_columns),row_number() over (partition by account_no order by tx_id desc ) as rn 
    from 
    (
      a.*,b.tx_id,b.balance,b.History
      from table1 a left outer join table2 b 
     on a.account_no=b.account_no
    )f
    )g where g.rn=1
    

    【讨论】:

    • 是的,似乎比我在问题中所做的更好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-05
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-18
    相关资源
    最近更新 更多