sqloracle-database

Query for every 10th row from a subsection of a whole table


I have a DB table that contains x million rows and a new row is created regularly (multiple per second).

There is a timestamp column but no date recorded. However, there is a unique ID assigned to each row entry and I'd like to be able to run a select query that allows me to select every 10th row where the unique ID is greater than the one entered so it gives me a snap shot of every 10th record greater than a unique ID value rather than the whole table (so using the unique ID value as a variable)

I have put together the query below but this pulls out every 10th row from the entire table and then gives me the ones where the UNIQUEID is greater than 33188498698899117300014

SELECT ID, TRANSTIMESTAMP, GLOBTIME, REMTIME
from (select ID as rn, t.*
      from TEST_TRANS t
     ) t
where rn - trunc(rn/10)*10 = 0 AND UNIQUEID > '33188498698899117300014'
ORDER BY ID DESC;

But this isn't exactly what I need as I need every 10th row greater than UNIQUEID '33188498698899117300014'

I'm sure this is straightforward but think I've hit a brick wall so any help would be much appreciated.


Solution

  • You want to filter in the inner query and use the ROW_NUMBER analytic function to number the rows and then filter in the outer query to get every 10th row:

    SELECT ID,
           TRANSTIMESTAMP,
           GLOBTIME,
           REMTIME
    FROM   (
      SELECT ID,
             TRANSTIMESTAMP,
             GLOBTIME,
             REMTIME,
             ROW_NUMBER() OVER (ORDER BY id) AS rn
      FROM   TEST_TRANS
      WHERE  UNIQUEID > '33188498698899117300014'
    )
    WHERE  MOD(rn, 10) = 0
    ORDER BY ID DESC
    

    Or, from Oracle 12:

    SELECT ID,
           TRANSTIMESTAMP,
           GLOBTIME,
           REMTIME
    FROM   TEST_TRANS
    WHERE  UNIQUEID > '33188498698899117300014'
    ORDER BY MOD(ROW_NUMBER() OVER (ORDER BY id), 10),
           id DESC
    FETCH FIRST 10 PERCENT ROWS ONLY
    

    Which, for the sample data:

    CREATE TABLE test_trans (ID PRIMARY KEY, TRANSTIMESTAMP, GLOBTIME, REMTIME, UNIQUEID UNIQUE) AS
    SELECT LEVEL,
           TIMESTAMP '1970-01-01 00:00:00' + LEVEL * INTERVAL '1' SECOND,
           TIMESTAMP '1970-01-01 00:00:00' + LEVEL * INTERVAL '1' SECOND,
           TIMESTAMP '1970-01-01 00:00:00' + LEVEL * INTERVAL '1' SECOND,
           TO_CHAR(
             CASE
             WHEN MOD(LEVEL, 10) IN (3, 4, 5, 7, 8)
             THEN 33188498698899117300014 + LEVEL
             ELSE 10000000000000000000000 + LEVEL
             END
           )
    FROM   DUAL
    CONNECT BY LEVEL <= 100;
    

    Both output:

    ID TRANSTIMESTAMP GLOBTIME REMTIME
    98 1970-01-01 00:01:38.000000000 1970-01-01 00:01:38.000000000 1970-01-01 00:01:38.000000000
    78 1970-01-01 00:01:18.000000000 1970-01-01 00:01:18.000000000 1970-01-01 00:01:18.000000000
    58 1970-01-01 00:00:58.000000000 1970-01-01 00:00:58.000000000 1970-01-01 00:00:58.000000000
    38 1970-01-01 00:00:38.000000000 1970-01-01 00:00:38.000000000 1970-01-01 00:00:38.000000000
    18 1970-01-01 00:00:18.000000000 1970-01-01 00:00:18.000000000 1970-01-01 00:00:18.000000000

    fiddle