Reputation: 484
I have 4 tables with the following relevant information I want to retrieve.
Table: Staff_profile (STAFF_ID, STAFF_USERNAME, STAFF_NAME, STAFF_JOB_ID, STAFF_FACULTY_ID, STAFF_OFF_TEL, STAFF_EMAIL) - holds staff information
Table: RFMUSERHISTORY (uh_staff_id, UH_DATETIME) - holds login history
Table: RFMUSERROLEJOBMAP (role_id, job_id ) - maps role-2-job [this is because job table pre-exists and this new app is only picking certain job ids to use against its own roles table
Table: RFMUSERROLE (USERROLE_CODE, USERROLE_ID) - holds user roles information
Now I want to get the last login (max date for that user in userhistory) details including role and staff details for any particular person who logs in. I have had trouble with my code and finally just resorted to selecting all the records for that user with the UH_datetime ordered desc so I can pick that latest topmost record.
Here is my current code (very inefficient as described above):
SELECT a.STAFF_ID, a.STAFF_USERNAME, a.STAFF_NAME, a.STAFF_JOB_ID, a.STAFF_FACULTY_ID,
a.STAFF_OFF_TEL, a.STAFF_EMAIL, to_CHAR(b.UH_DATETIME,'Dy DD-MM-YYYY HH24:MI:SS')
AS UH_DATETIME, e.USERROLE_CODE, e.USERROLE_ID
FROM STAFF_PROFILE a
LEFT JOIN RFMUSERHISTORY b ON STAFF_ID=b.uh_staff_id
LEFT JOIN RFMUSERROLEJOBMAP d ON a.STAFF_JOB_ID=d.job_id
LEFT JOIN RFMUSERROLE e ON d.role_id=e.userrole_id
WHERE STAFF_ID=:eid1 ORDER BY b.UH_DATETIME DESC
Upvotes: 0
Views: 3030
Reputation: 231661
You could use an analytic function to rank the rows and then select the most recent one. If you're really just selecting the data for a single STAFF_ID
, this is probably no more efficient than nesting your original query in an outer query that selects the row using a ROWNUM
predicate. If you are selecting the data for multiple staff members, however, this should be more efficient.
SELECT *
FROM (
SELECT a.STAFF_ID,
a.STAFF_USERNAME,
a.STAFF_NAME,
a.STAFF_JOB_ID,
a.STAFF_FACULTY_ID,
a.STAFF_OFF_TEL,
a.STAFF_EMAIL,
to_CHAR(b.UH_DATETIME,'Dy DD-MM-YYYY HH24:MI:SS') AS UH_DATETIME,
e.USERROLE_CODE,
e.USERROLE_ID,
dense_rank() over (partition by a.staff_id order by b.uh_datetime desc) rnk
FROM STAFF_PROFILE a
LEFT JOIN RFMUSERHISTORY b ON STAFF_ID=b.uh_staff_id
LEFT JOIN RFMUSERROLEJOBMAP d ON a.STAFF_JOB_ID=d.job_id
LEFT JOIN RFMUSERROLE e ON d.role_id=e.userrole_id
WHERE STAFF_ID=:eid1
)
WHERE rnk = 1
Upvotes: 3
Reputation: 238068
Oracle doesn't send rows over the network before you ask for them. If your client code only request the first row, your query should be efficient enough.
Another option is to limit Oracle to one row with rownum
:
where rownum = 1
Upvotes: 1