Home > Enterprise >  Select top 10 records of a certain key sql
Select top 10 records of a certain key sql

Time:10-30

I have 2 tables connected with each other, for simplicity lets say ID of the 1st is connected to UserCreated_FK of the 2nd table.

Table A:

ID NAME
237 Gal
240 blah
250 blah2

in the parallel table ( aka table B ) I have the following:

UserCreated_FK col2
237 10/10
20 more rows of 237 20 more rows of 237
240 11/10
5 more rows of 240 20 more rows of 240
250 12/10
14 more rows of 250 20 more rows of 250

Result wanted: id.237 x10 last(might be sorted by date col I have).

no 240 (cause less than 10).

id.250 x10 last records(might be sorted by date col I have).

My task is to check which of those IDs(person'sIds) have more then 10 records on table B ( because table A is just the ids and names not the actual records of them.

So for example, ID no.237 got 19 records on table B I want to be able to pull the last 10 records of that user.

And again, the condition is only users that have more than 10 records, then to pull the last of 10 of those..

Hope I was understandable, thanks a lot, any help will be appreciated!

CodePudding user response:

You can join the two tables and then use analytic functions:

SELECT *
FROM   (
  SELECT a.id,
         a.name,
         b.col2,
         b.datetime,
         COUNT(*) OVER (PARTITION BY a.id) AS b_count,
         ROW_NUMBER() OVER (PARTITION BY a.id ORDER BY b.datetime DESC) AS rn
  FROM   table_a a
         INNER JOIN table_b b
         ON (a.id = b.user_created_fk)
)
WHERE  b_count >= 10
AND    rn <= 10;

If you just want the values from table_b then you do not need to use table_a:

SELECT *
FROM   (
  SELECT b.*,
         COUNT(*) OVER (PARTITION BY b.user_created_fk) AS b_count,
         ROW_NUMBER() OVER (
           PARTITION BY b.user_created_fk ORDER BY b.datetime DESC
         ) AS rn
  FROM   table_b b
)
WHERE  b_count >= 10
AND    rn <= 10;

CodePudding user response:

The WITH clause is here just to generate some sample data and it is not a part of the answer.

WITH
    tbl_a AS
        (
            Select 237 "ID", 'Gal' "A_NAME" From Dual Union All
            Select 240 "ID", 'blah' "A_NAME" From Dual Union All
            Select 250 "ID", 'blah2' "A_NAME" From Dual 
        ),
    tbl_b AS
        (
            Select 237 "FK_ID", SYSDATE - (21 - LEVEL) "A_DATE" From Dual Connect By LEVEL <= 20 Union All
            Select 240 "FK_ID", SYSDATE - (6 - LEVEL) "A_DATE" From Dual Connect By LEVEL <= 5 Union All
            Select 250 "FK_ID", SYSDATE - (15 - LEVEL) "A_DATE" From Dual Connect By LEVEL <= 14 
        )
Select
    a.ID,
    a.A_NAME,
    b.TOTAL_COUNT "TOTAL_COUNT",
    b.RN "RN",
    b.A_DATE
From
    tbl_a a
Inner Join
    (   Select FK_ID, A_DATE, ROW_NUMBER() OVER(Partition By FK_ID Order By FK_ID, A_DATE DESC) "RN", Count(*) OVER(Partition By FK_ID) "TOTAL_COUNT" From tbl_b ) b ON(b.FK_ID = a.ID)
WHERE
  b.RN <= 10 And b.TOTAL_COUNT > 10

With your sample data the main SQL joins tbl_a with a subquery by FK_ID = ID. The subquery uses analytic functions to get total rows per FK_ID (in tbl_b) and gives row numbers (partitioned by FK_ID) to the dataset. All the rest is in the Where clause.
Result:

/*
        ID A_NAME TOTAL_COUNT         RN A_DATE  
---------- ------ ----------- ---------- ---------
       237 Gal             20          1 29-OCT-22 
       237 Gal             20          2 28-OCT-22 
       237 Gal             20          3 27-OCT-22 
       237 Gal             20          4 26-OCT-22 
       237 Gal             20          5 25-OCT-22 
       237 Gal             20          6 24-OCT-22 
       237 Gal             20          7 23-OCT-22 
       237 Gal             20          8 22-OCT-22 
       237 Gal             20          9 21-OCT-22 
       237 Gal             20         10 20-OCT-22 
       250 blah2           14          1 29-OCT-22 
       250 blah2           14          2 28-OCT-22 
       250 blah2           14          3 27-OCT-22 
       250 blah2           14          4 26-OCT-22 
       250 blah2           14          5 25-OCT-22 
       250 blah2           14          6 24-OCT-22 
       250 blah2           14          7 23-OCT-22 
       250 blah2           14          8 22-OCT-22 
       250 blah2           14          9 21-OCT-22 
       250 blah2           14         10 20-OCT-22 
*/

Regards...

  • Related