Home > Software design >  How can I solve sql record grouping problem?
How can I solve sql record grouping problem?

Time:02-12

I'm trying to figure out a way to return results by using the group by function.

Is it possible to have a group by ignoring the NULL field. So that it does not group NULLs together because I still need all the rows where the specified field is NULL.

my records example TABLEX

id status mode update_date
1 null 0 13:46
1 null 1 12:22
1 1 null 15:00
1 0 null 15:55

i want to group last records with not null columns.

i tried this query but it is not success:

SELECT id, status, mode, update_date FROM TABLEX ORDER BY update_date GROUP BY id

i want to get this result:

id status mode update_date
1 0 0 15:55

how can i solve this situation.

CodePudding user response:

NOTES:

  • This is running on oracle 18c.
  • There's GOT to be a better way.... and this isn't tested w/ all edge cases I could think of... But it appears to be working....

DEMO: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=be87b5778616a4732db3a3c4787804e0

WITH CTE AS (SELECT 1 ID, null STATUS,0 "MODE", '13:46' UPDATE_DATE from dual UNION ALL
         SELECT 1,null,1,'12:22' from dual UNION ALL
         SELECT 1,1,null,'15:00' from dual UNION ALL
         SELECT 1,0,null,'15:55' from dual)


SELECT A.ID, Z.Status, Y."MODE", max(A.Update_Date) UD
FROM CTE A
CROSS APPLY (SELECT B.Status FROM CTE B WHERE B.ID = A.ID and B.Status is not null ORDER BY UPDATE_DATE DESC FETCH FIRST 1 ROW ONLY) Z
CROSS APPLY (SELECT B."MODE" FROM CTE B WHERE B.ID = A.ID and B."MODE" is not null ORDER BY UPDATE_DATE DESC FETCH FIRST 1 ROW ONLY) Y
GROUP BY ID, Z.Status, Y."MODE"


 ---- -------- ------ ------- 
| ID | STATUS | MODE |  UD   |
 ---- -------- ------ ------- 
|  1 |      0 |    0 | 15:55 |
 ---- -------- ------ ------- 
  • I didn't bother with data type casting for the update date so long as the time is in a 24 hour format the results would be the same so I didn't take the time.
  • So cross apply is running the inline queries once for each row in the main table and obtaining the status or mode following the rule of not null value and must have the highest Update_Date. I thought First_Value analytic would work; but I couldn't get it working... (though I was using 11 at the time)
  • Since it will return the same values for all rows within an ID, grouping by it allows us to consolidate back into 1 record.
  • first_value may work on 18 I didn't try it there...

More testing: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=705747c5b5f0e8414a2561fa82842fb7

CodePudding user response:

Here is a complete script creating the table and returning what you want ( and I believe with the logic that you want):

CREATE TABLE tablex (
    id int,
    status int,
    mode int,
    update_date time);
INSERT INTO tablex values(1,null,0,'13:46');
INSERT INTO tablex values(1,null,1,'12:22');
INSERT INTO tablex values(1,1,null,'15:00');
INSERT INTO tablex values(1,0,null,'15:55');
select 
    t.id, 
    t.status,
    t.mode, 
    t.update_date 
from 
    tablex t
join 
(   select id , max(update_date) as u
    from tablex group by id) pre on t.id = pre.id
    and t.update_date = pre.u;
drop table tablex;

NB I don't have Oracle but this is working on mySQL.

  • Related