Home > Enterprise >  Retrieve the last value of each data group - Oracle SQL
Retrieve the last value of each data group - Oracle SQL

Time:05-01

I’m having trouble on a query right now to retrieve only the last value saved for each group of results.

I explain myself with a table. I have these values:

| date   |  analyses | result|
| ------ | --------- | ----- |
| date 8 |analysis A |  10   |
| date 7 |analysis A |  15   |
| date 6 |analysis C |  12   |
| date 5 |analysis A |  13   |
| date 4 |analysis B |  17   |
| date 3 |analysis A |  25   |
| date 2 |analysis B |  20   |
| date 1 |analysis C |  10   |

I retrieve in my query all the results obtained for 3 types of analyses and I display their creation date from the most recent to the oldest.

I would now like to improve my query if possible so that it only gives me the last values for each analysis.

The expected result is:

| date   | analyses  | result|
| -----  | --------  | ----- |
| date 8 |analysis A |  10   |
| date 6 |analysis C |  12   |
| date 4 |analysis B |  17   |

My request now looks like this:

SELECT
    date,
    analyses,
    results
FROM
    table_results,
    table_analyses,
WHERE
    analyse in ('analysis A','analysis B','analysis C')
ORDER BY date DESC

I tried to use GROUP BY on the attribute analyses but without success (error: is not a GROUP BY expression...).

If anyone has an idea thank you in advance,

Have a good day

CodePudding user response:

To me, it looks as this:

Sample data (didn't feel like typing too much; read what mathguy commented. Whatever C_DATE is (should be DATE datatype), query that follows will still work):

SQL> select * from test;

    C_DATE ANALYSES       RESULT
---------- ---------- ----------
         8 a                  10
         7 a                  15
         6 c                  12
         5 a                  13
         4 b                  17
         3 a                  25
         2 b                  20
         1 c                  10

8 rows selected.

First rank rows per each analyses by c_date in descending order (so that the "last" date ranks as the highest), and then fetch these rows:

SQL> with temp as
  2    (select c_date, analyses, result,
  3       rank() over (partition by analyses order by c_date desc) rnk
  4     from test
  5    )
  6  select c_date, analyses, result
  7  from temp
  8  where rnk = 1
  9  order by analyses;

    C_DATE ANALYSES       RESULT
---------- ---------- ----------
         8 a                  10
         4 b                  17
         6 c                  12

SQL>

CodePudding user response:

Create Table:

CREATE TABLE TEST_TABLE(ADATE VARCHAR(20), ANALYSES VARCHAR(20), RESULT VARCHAR(20))

INSERT INTO TEST_TABLE VALUES('date 8', 'analysis A', '10');
INSERT INTO TEST_TABLE VALUES('date 7', 'analysis A', '15');
INSERT INTO TEST_TABLE VALUES('date 6', 'analysis C', '12');
INSERT INTO TEST_TABLE VALUES('date 5', 'analysis A', '13');
INSERT INTO TEST_TABLE VALUES('date 4', 'analysis B', '17');
INSERT INTO TEST_TABLE VALUES('date 3', 'analysis A', '25');
INSERT INTO TEST_TABLE VALUES('date 2', 'analysis B', '20');
INSERT INTO TEST_TABLE VALUES('date 1', 'analysis C', '10');

SELECT * FROM TEST_TABLE: https://i.stack.imgur.com/PnzCm.png


Solution:

SELECT
    MAX(ADATE) KEEP(DENSE_RANK LAST ORDER BY ADATE) AS ADATE
    , ANALYSES
    , MAX(RESULT) KEEP(DENSE_RANK LAST ORDER BY ADATE) AS RESULT
FROM
    TEST_TABLE
GROUP BY
    ANALYSES
ORDER BY
    ADATE DESC

Result: https://i.stack.imgur.com/DpsDO.png

CodePudding user response:

You can still get the result you want using a GROUP BY but you would have to break your attempt into 2 levels.

Assuming you already have a query, table or view that gets you the following - call it "test", so if I call SELECT * FROM test, I get the below:

| date   |  analyses | result|
| ------ | --------- | ----- |
| date 8 |analysis A |  10   |
| date 7 |analysis A |  15   |
| date 6 |analysis C |  12   |
| date 5 |analysis A |  13   |
| date 4 |analysis B |  17   |
| date 3 |analysis A |  25   |
| date 2 |analysis B |  20   |
| date 1 |analysis C |  10   |

You haven't given us data types here, so I have assumed your date column is a string (if it's a different data type you can still cast this to an integer or number type).

  1. I defined a temptable where I extracted the number part of your date (instead of "date 8" I would just use 8) and casted it to be a number. This was saved as the "date_number" column and that way you can run group by operations like MAX on it

  2. I did a GROUP BY on the temptable to get the MAX date_number value for each analyses value

  3. I called all the values in the original table (select * from test), with a WHERE clause, telling it that I wanted all the rows where my date was equal to the values in part (2) - so basically all the rows where there was a maximum date for each analyses type

In short the code looks like this

with  temptable as
        (select to_number(substr(to_char(the_date),6,1)) as date_number, 
                analyses, 
                result
        from test)
select * 
from test
where 
    to_number(substr(to_char(the_date),6,1)) in 
                   (select max(date_number) from temptable
                    group by analyses)
  • Related