简体   繁体   中英

Selecting the latest record within a table

I have ant an Oracle v11 database, and whilst I do not have the schema definition of the tables, I have illustrated what I am trying to achieve below.

This is what the table looks like

I am trying to transform the data by selecting only the latest rows, the table keeps an history of changes, I am not interested in the changes only the latest value for every present issue

This is what I have so far.

select issueno,
  case (when fieldname = 'name' then string_value end) name,
  case (when fieldname = 'point' then string_value end) point
from issues
where issueno = 1234

The issue with the query above is that it returns 4 rows, I would like to return only a single row.

Assuming that you want to have the latest record by the column load_date

select issueno,
  case (when fieldname = 'name' then string_value end) name,
  case (when fieldname = 'point' then string_value end) point
from issues
where issueno = 1234 and 
(fieldname , load_date) in (select fieldname ,max(load_date) from issues where issueno=1234 group by fieldname)

I would use a subquery + window function to achieve what you asked for (assuming you use are basing load_date to determine the latest record)

select issueno,
  case (when fieldname = 'name' then string_value end) name,
  case (when fieldname = 'point' then string_value end) point
from 
(
SELECT name, point, ROW_NUMBER() OVER(PARTITION BY ISSUENO, FIELDNAME ORDER BY LOAD_DATE DESC) RN 
FROM issues
)
where issueno = 1234
AND RN = 1

The syntax ROW_NUMBER() OVER ([query_partition_clause] order_by_clause) is actually a window function that assign a ranking to each rows governed by how you declare the rule in [query_partition_clause] order_by_clause

See whether something like this helps; read comments within code.

SQL> with issues (issueno, fieldname, string_value,
  2               transition_date, transition_id, load_date)
  3    as
  4    -- sample data; you have it in a table, don't type that
  5    (select 1234, 'name', null , date '2021-01-01', 1, date '2021-01-02' from dual union all
  6     select 1234, 'name', 'Tom', date '2021-02-11', 2, date '2021-02-12' from dual union all
  7     select 1234, 'point', '0' , date '2021-02-04', 3, date '2021-02-05' from dual union all
  8     select 1234, 'point', '5' , date '2021-02-10', 5, date '2021-02-11' from dual
  9    ),
 10  -- query you need begins here
 11  temp as
 12    -- rank values partitioned by ISSUENO and FIELDNAME, sorted by TRANSITION_ID
 13    (select issueno, fieldname, string_value,
 14       row_number() over (partition by issueno, fieldname
 15                          order by transition_id desc) rn
 16     from issues
 17    )
 18  select issueno,
 19    max(case when fieldname = 'name'  then string_value end) name,
 20    max(case when fieldname = 'point' then string_value end) point
 21  from temp
 22  where rn = 1
 23  group by issueno;

   ISSUENO NAME       POINT
---------- ---------- ----------
      1234 Tom        5

SQL>

You can get the latest date by using LAST ORDER BY clause within the MAX() KEEP (..) values for transition_date (or load_date column, depending on which you mean replace within the query ) such as

WITH i AS
(
SELECT CASE WHEN fieldname = 'name' THEN
             MAX(string_value) KEEP (DENSE_RANK LAST ORDER BY transition_date)
                               OVER (PARTITION BY issue_no, fieldname) 
             END AS name,
       CASE WHEN fieldname = 'point' THEN
             MAX(string_value) KEEP (DENSE_RANK LAST ORDER BY transition_date)
                               OVER (PARTITION BY issue_no, fieldname) 
             END AS point                
  FROM issues 
)
SELECT MAX(name) AS name, MAX(point) AS point 
  FROM i

But, if ties( equal values ) occur for the related date values, then consider using DENSE_RANK() function in order to compute the values returning equal to 1 along with ROW_NUMBER() to be able to use with the JOIN clause in the main query such as

WITH i AS
(
SELECT i.*,
       DENSE_RANK() OVER ( PARTITION BY issue_no, fieldname 
                               ORDER BY transition_date DESC) AS dr,
       ROW_NUMBER() OVER ( PARTITION BY issue_no, fieldname 
                               ORDER BY transition_date DESC) AS rn
  FROM issues i
)
SELECT i1.string_value AS name, i2.string_value AS point
  FROM ( SELECT string_value, rn FROM i WHERE dr = 1 AND fieldname = 'name'  ) i1
  FULL JOIN ( SELECT string_value, rn FROM i WHERE dr = 1 AND fieldname = 'point' ) i2
    ON i2.rn = i1.rn

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM