Oracle:左连接非常大 table 并将连接的行限制为具有最大字段值的行
Oracle: Left join very big table and limit the joined rows to one with the largest field value
我有两个 table。第二个通过 m_id.
引用第一个
主要table
M_ID | M_FIELD
1 | 'main1'
2 | 'main2'
3 | 'main3'
亚table
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
我需要加入这两个 tables(按 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?
(我会post它在底部)
但问题是 Sub-Table
非常大(实际上是一个带有一些内部计算的视图)并且这种子查询工作时间太长。所以我想我需要先通过 m_id 过滤掉 table ,然后才找到最大 S_ORDER
[=25= 的字段]
我需要像这样简单的东西(失败是因为二级子查询在外面看不到 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
table 工作太慢):
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;
我们使用的DB是Oracle 10g
非常感谢您的帮助
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)
试试这个
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
我有两个 table。第二个通过 m_id.
引用第一个主要table
M_ID | M_FIELD
1 | 'main1'
2 | 'main2'
3 | 'main3'
亚table
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
我需要加入这两个 tables(按 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?
(我会post它在底部)
但问题是 Sub-Table
非常大(实际上是一个带有一些内部计算的视图)并且这种子查询工作时间太长。所以我想我需要先通过 m_id 过滤掉 table ,然后才找到最大 S_ORDER
[=25= 的字段]
我需要像这样简单的东西(失败是因为二级子查询在外面看不到 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
table 工作太慢):
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;
我们使用的DB是Oracle 10g
非常感谢您的帮助
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)
试试这个
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