2016-07-04 2 views
1

У меня есть две таблицы. Второй ссылается на первый на m_id.Oracle: Left join очень большой стол и ограничить объединенные строки до одного с наибольшим значением поля

Главная таблица

M_ID | M_FIELD 
    1 | 'main1' 
    2 | 'main2' 
    3 | 'main3' 

Суб стол

S_ID | S_FIELD | S_ORDER | M_ID 
    1 | 'sub1-1' | 1 | 1 
    2 | 'sub1-2' | 2 | 1 
    3 | 'sub1-3' | 3 | 1 
    4 | 'sub2-1' | 1 | 2 
    5 | 'sub2-2' | 2 | 2 
    6 | 'sub2-3' | 3 | 2 
    7 | 'sub3-1' | 1 | 3 
    8 | 'sub3-2' | 2 | 3 
    9 | 'sub3-3' | 3 | 3 

Мне нужно соединить эти две таблицы (по M_ID), но из Sub-table мне нужно только строку с самым большим значение S_ORDER.

Таким образом, ожидаемый результат запроса:

M_ID | M_FIELD | S_FIELD 
    1 | 'main1' | 'sub1-3' 
    2 | 'main2' | 'sub2-3' 
    3 | 'main3' | 'sub3-3' 

Существует рабочий раствор с аналитической функцией в ответ на этот вопрос: How do I limit the number of rows returned by this LEFT JOIN to one? (я отправлю его на дно) Но проблема в том, что Sub-Table очень большой (и на самом деле представляет собой представление с некоторыми внутренними вычислениями), и этот подзапрос работает слишком долго. Поэтому я полагаю, что нужно отфильтровать таблицу по m_id первого и только после этого найти поле с наибольшим S_ORDER

мне нужно что-то простое, как это (который терпит неудачу, потому что второй уровень подзапрос не видит M.M_ID поле снаружи):

SELECT m.*, 
     (SELECT s_field 
     FROM (SELECT s_field 
       FROM t_sub s 
       WHERE s.m_id = m.m_id 
       ORDER BY s_order DESC) 
     WHERE ROWNUM = 1) s_field 
FROM t_main m; 

код для создания и заполнения тестовой схемы:

CREATE TABLE t_main (m_id NUMBER PRIMARY KEY, 
        m_field VARCHAR2(10)); 
CREATE TABLE t_sub (s_id NUMBER PRIMARY KEY, 
        s_field VARCHAR2(10), 
        s_order NUMBER, 
        m_id NUMBER); 
INSERT INTO t_main VALUES (1,'main1'); 
INSERT INTO t_main VALUES (2,'main2'); 
INSERT INTO t_main VALUES (3,'main3'); 
INSERT INTO t_sub VALUES (1,'sub1-1', 1, 1); 
INSERT INTO t_sub VALUES (2,'sub1-2', 2, 1); 
INSERT INTO t_sub VALUES (3,'sub1-3', 3, 1); 
INSERT INTO t_sub VALUES (4,'sub2-1', 1, 2); 
INSERT INTO t_sub VALUES (5,'sub2-2', 2, 2); 
INSERT INTO t_sub VALUES (6,'sub2-3', 3, 2); 
INSERT INTO t_sub VALUES (7,'sub3-1', 1, 3); 
INSERT INTO t_sub VALUES (8,'sub3-2', 2, 3); 
INSERT INTO t_sub VALUES (9,'sub3-3', 3, 3); 
COMMIT; 

рабочего раствора, упомянутого выше (работает слишком медленно с крупом е T_SUB стол):

SELECT m.*, 
     s.s_field 
FROM t_main m 
LEFT JOIN 
    (SELECT * 
    FROM 
    (SELECT ts.*, 
      ROW_NUMBER() OVER (PARTITION BY m_id 
           ORDER BY s_order DESC) AS seq 
     FROM t_sub ts) 
    WHERE seq = 1) s ON s.m_id = m.m_id; 

БД мы используем Oracle 10g

Большое спасибо за вашу помощь

ответ

2

попробовать это

SELECT m.*, 
     (select s.s_field 
      from t_sub s 
     where s.m_id = m.m_id 
      and s.s_order = (select max(s_order) from t_sub where t_sub.m_id = s.m_id) 
      and rownum = 1) 
FROM t_main m 

или вы можете попробовать это (это ваш код, но некоторые изменения)

SELECT m.*, 
     (select s.s_field from 
     (SELECT s_field, m_id 
      FROM t_sub 
     --where t_sub.m_id = m.m_id 
     order by s_order DESC) s 
     where s.m_id = m.m_id 
      and rownum = 1) 
FROM t_main m 
1
select t.*, s.s_field from t_main t 
left join (select m_id, min(s_field) keep(dense_rank first order by s_order desc) as s_field 
     from t_sub group by m_id) s on (s.m_id = t.m_id) 
+0

Спасибо! Это работает, но все еще очень долго – Dany

 Смежные вопросы

  • Нет связанных вопросов^_^