Returning a single row on an INNER JOIN
I would like to return the first row only from an inner join. I have two tables:
Rows in TABLE_D and TABLE_E can have identical creation dates so I am first getting the MAX(creationdate) and then then MAX(id) from this set. Here's my complete query:
SELECT a.id as A_ID, b.id as B_ID, c.id as C_ID, d.id as D_ID, e.id as E_ID, d.CREATIONDATE, a.REFNUMBER, a.DATECREATED, a.INFO, e.COST, FROM TABLE_A a INNER JOIN TABLE_B b ON (b.id = a.id) INNER JOIN TABLE_C c ON (c.id = b.id) INNER JOIN TABLE_D d ON ( c.i = ( select d.id FROM TABLE_D WHERE TABLE_D.id = c.id AND TABLE_D.id = ( select max(id) from TABLE_D t1 where c_id = c.id and CREATIONDATE = ( select max(CREATIONDATE) from TABLE_D t2 where t2.c_id = t1.c_id ) ) ) ) INNER JOIN TABLE_E e ON ( d.i = ( select e.d_id from TABLE_E where d_id = d.id AND id = ( select max(id) from e t1 where e.d_id = d.id and CREATIONDATE = ( select max(CREATIONDATE) from TABLE_E t2 where t2.d_id = t1.d开发者_开发问答_id ) ) ) )
My subquery to get all rows with a max creationdate and from that the max id works fine when I call it on it's own but when I add it to an INNER JOIN (see above) I am getting a row for each matching row in table D and table E. What I want is one row per TABLE_A.id showing only the latest row from TABLE_D associated with TABLE_C and the latest from TABLE_E associated with TABLE_D.
For example, the id's in my result set look like this at the moment:
-------------------------------------------------------------------------- A_ID B_ID C_ID D_ID E_ID -------------------------------------------------------------------------- 1 101 201 301 401 1 101 201 301 402 1 101 201 301 403 1 101 201 302 404 1 101 201 302 405 1 101 201 302 406
what I need is this:
-------------------------------------------------------------------------- A_ID B_ID C_ID D_ID E_ID -------------------------------------------------------------------------- 1 101 201 302 406
Thanks in advance for your help.
Use the analytical function ROW_NUMBER() which is available in oracle11g
SELECT *
FROM
(
SELECT
a.id as A_ID,b.id as B_ID,c.id as C_ID,d.id as D_ID,e.id as E_ID,
d.CREATIONDATE,a.REFNUMBER,a.DATECREATED,a.INFO,e.COST,
row_number() over (
partition by a.id, b.id, c.id
order by d.CREATIONDATE DESC, d.id desc, e.CREATIONDATE DESC, e.id desc) RN
FROM TABLE_A a
INNER JOIN TABLE_B b ON (b.id = a.id)
INNER JOIN TABLE_C c ON (c.id = b.id)
INNER JOIN TABLE_D d ON d.c_id = c.id
INNER JOIN TABLE_E e ON e.d_id = d.id
) N
WHERE RN = 1
Just make sure the PARTITION and ORDER BY clauses are correct
partition by a.id, b.id, c.id
=> start numbering from 1 again when any one of these changes
order by d.CREATIONDATE DESC, d.id desc, e.CREATIONDATE DESC, e.id desc)
=> number the rows in this order
What I would do is move the inner query to select clause. I will just keep direct mapping while filtering
SELECT
a.id as A_ID,
b.id as B_ID,
c.id as C_ID,
(select max(d.id) from d where d.id =c.id) as d_id)
FROM
TABLE_A a
INNER JOIN TABLE_B b ON (b.id = a.id)
INNER JOIN TABLE_C c ON (c.id = b.id)
You could insert your query in a subquery and use a WHERE ROWNUM<2 filter.
SELECT * FROM
(/* Your SQL */)
WHERE ROWNUM < 2
Maybe this would work for you?
SELECT TOP 1 a.id as A_ID, b.id as B_ID, c.id as C_ID, d.id as D_ID, e.id as E_ID, d.CREATIONDATE, a.REFNUMBER, a.DATECREATED, a.INFO, e.COST, FROM TABLE_A a INNER JOIN TABLE_B b ON (b.id = a.id) INNER JOIN TABLE_C c ON (c.id = b.id) INNER JOIN TABLE_D d ON (c.i = d.id) INNER JOIN TABLE_E e ON ( d.i = e.id ) ORDER BY d.creationdate DESC, e.creationdate DESC
精彩评论