How do you call previous row in a where clause? - sql

I am trying to figure out how to get rid of results that occur close together. For example the rows have a create timestamp (source_time). I want to remove results that occur within 10 seconds of each other.
I thought lag() might do it, but I can't use that in the where clause.
select *
from table
where source_time - previous(source_time) >= 10 second
Very rough code, but I am not sure how to call the previous source time. I have translated them to timestamps and used timestamp_diff(source_time, x, second) >= 10 but not sure how to make x the previous value.
Hopefully this is clear.

You can do this with subqueries.
delete table t1
where t1.id in (
select t2.id
from (
select
id,
source_time - lag(source_time) over (order by source_time) as time_diff
from table
) t2
where t2.time_diff < 10 second
)
Keep in mind this can potentially leave large gaps in your records if. For example, if you get a row every 9 seconds for an hour you'll delete all but the last record in that hour.
You might instead partition the source_time every 10 seconds and delete anything with a row_number > 1.
delete table t1
where t1.id in (
select t2.id
from (
select
id,
source_time,
row_number() over(
partition by source_time - make_interval(second => extract(second from source_time) % 10)
order by source_time asc
) rownum
from table
) t2
where rownum > 1
)

Related

Select ONLY second row if Date and Time are the same (MS SQL) [duplicate]

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 1 year ago.
A date, time, number is produced every 1 hour and this will be Try number 1. However, there are times when there is a second Try will happen to collect the number for the same date and Time.
I would like to select Date, Time and Number for Try number 2 instead of number 1 if it exist.
Output needed
Code
SELECT Date, Time, Number, Try
FROM DB1 DB1
WHERE (Date>={ts '2021-01-26 00:00:00'})
ORDER BY Date, Time
Use row_number and filter:
select Date, Time, Number, Try
from
(
SELECT Date, Time, Number, Try,
row_number() over(partition by Date, Time order by Try desc) as rn
) s
where rn=1
It will selecft only the last try per date, time
You can use not exists, if you specifically want "2" (as the question states):
select t.*
from db1 t
where t.try = 2 or
(t.try = 1 and
not exists (select 1
from db1 t2
where t2.date = t.date and t2.time = t.time and
t2.try = 1
)
);
SELECT * FROM (
SELECT ROW_NUMBER() OVER(ORDER BY ID) AS RoNum
, ID --Add any fields needed here (or replace ID by *)
FROM TABLE_NAME
) AS tbl
WHERE (Date>={ts '2021-01-26 00:00:00'})
OFFSET 0 ROWS
FETCH NEXT 1 ROWS ONLY;
The OFFSET clause skips zero rows and the FETCH clause returns the first row.
Reference: https://www.sqltutorial.org/sql-fetch/

DELETE query with Common Table Expression ("WITH AS " clause)

I am trying to delete 41,6% of my old rows from my oracle data table ( senstrig is a date format):
DELETE FROM
(WITH RS AS (SELECT * FROM OLD_WIFISIGN WHERE SENSID= 1 ORDER BY SENSTRIG ASC))
WHERE ROWNUM <= (SELECT COUNT (*)/ 2.4 FROM RS);
But it returns an error:
ORA-00928 missing SELECT
I have already tried several versions but with no luck.
Could you please help me how can I make this "delete from" runnable?
Test table, 1000 rows, all with sensid = 1:
create table old_wifisign (sensid, senstrig) as (
select 1, trunc(sysdate) - level
from dual connect by level <= 1000);
Delete:
delete
from old_wifisign
where rowid in (
select rowid
from (
select rowid, row_number() over (order by senstrig) / count(1) over () rto
from old_wifisign
where sensid = 1 )
where rto <= .416)
Result: 416 rows with oldest senstrig deleted. Note that only sensid 1 is taken into calculations here, as in your query.
To delete 41,6% of old rows check fist the boundary date to delete and than use it.
The analytic function PERCENT_RANK gives you the youngest senstrig you do not want to delete.
with perc_rank as (
select SENSID, SENSTRIG,
PERCENT_RANK() OVER (ORDER BY senstrig) AS pr
from old_wifisign)
select max(SENSTRIG) from perc_rank
where pr < .416
Than you simple takes this date and performs a DELETE
delete from old_wifisign
where SENSTRIG <
(with perc_rank as (
select SENSID, SENSTRIG,
PERCENT_RANK() OVER (ORDER BY senstrig) AS pr
from old_wifisign)
select max(SENSTRIG) from perc_rank
where pr < .416
);
Anyway you should take soem care considering ties - thing about a case when half of the rows in the table have identical senstrig
Put WITH before DELETE:
WITH RS AS (SELECT * FROM OLD_WIFISIGN WHERE SENSID= 1 ORDER BY SENSTRIG ASC)
DELETE FROM OLD_WIFISIGN
WHERE ROWNUM <= (SELECT COUNT (*)/ 2.4 FROM RS);
Still a bit weird, what is the purpose of the order by?

How to skip/offset rows in Oracle database?

I am writing a very simple query for an Oracle DB (version 9).
Somehow I can get first 5 rows:
select * from cities where rownum <= 5
But skipping 5 rows returns an empty result:
select * from cities where rownum >= 5
Using:
Oracle SQL Developer
Oracle DB version 9
Why is the second query returning an empty result?
In Oracle Database 12c (release 1) and above, you can do this very simple, for skip 5 rows:
SELECT * FROM T OFFSET 5 ROWS
and for skip 5 rows and take 15 rows:
SELECT * FROM T OFFSET 5 ROWS FETCH NEXT 15 ROWS ONLY
You can use the following query to skip the first not n of rows.
select * from (
select rslts.*, rownum as rec_no from (
<<Query with proper order by (If you don't have proper order by you will see weird results)>>
) rslts
) where rec_no > <<startRowNum - n>>
The above query is similar to pagination query below.
select * from (
select rslts.*, rownum as rec_no from (
<<Query with proper order by (If you don't have proper order by you will see weird results)>>
) rslts where rownum <= <<endRowNum>>
) where rec_no > <<startRowNum>>
Your cities query:
select * from (
select rslts.*, rownum as rec_no from (
select * from cities order by 1
) rslts
) where rec_no > 5 <<startRowNum>>
Note: Assume first column in cities table is unique key
Oracle increments rownum each time it adds a row to the result set. So saying rownum < 5 is fine; as it adds each of the first 5 rows it increments rownum, but then once ruwnum = 5 the WHERE clause stops matching, no more rows are added to the result, and though you don't notice this rownum stops incrementing.
But if you say WHERE rownum > 5 then right off the bat, the WHERE clause doesn't match; and since, say, the first row isn't added to the result set, rownum isn't incremented... so rownum can never reach a value greater than 5 and the WHERE clause can never match.
To get the result you want, you can use row_number() over() in a subquery, like
select *
from (select row_number() over() rn, -- other values
from table
where -- ...)
where rn > 5
Update - As noted by others, this kind of query only makes sense if you can
control the order of the row numbering, so you should really use row_number() over(order bysomething) where something is a useful ordering key in deciding which records are "the first 5 records".
rownum is being increased only when a row is being output, so this type of condition won't work.
In any case, you are not ordering your rows, so what's the point?
Used row_number() over (order by id):
select * from
(select row_number() over (order by id) rn, c.* from countries c)
where rn > 5
Used ROWNUM:
select * from
(select rownum rn, c.* from countries c)
where rn > 5
Important note:
Using alias as countries c instead of countries is required! Without, it gives an error "missing expression"
Even better would be:
select * from mytab sample(5) fetch next 1 rows only;
Sample clause indicates the probability of each row getting picked up in the sampling process. FETCH NEXT clause indicates the number of rows you want to select.
With this code, you can query your table with skip and take.
select * from (
select a.*, rownum rnum from (
select * from cities
) a
) WHERE rnum >= :skip + 1 AND rnum <= :skip + :take
This code works with Oracle 11g. With Oracle 12, there is already a better way to perform this queries with offset and fetch

Get average and standard deviation on difference between row values

Given the following table:
CREATE TABLE datapoints
(
id serial NOT NULL,
datasource text,
"timestamp" integer,
value text,
CONSTRAINT datapoints_pkey PRIMARY KEY (id)
)
How can I calculate the average and standard deviation of the difference in timestamp1 from one row to the next?
What I mean is, if the data looks like this:
timestamp
---------
1385565639
1385565641
1385565643
I would like to calculate the average and standard deviation on the following data:
timestamp difference
--------------------
0
2
2
Is this even possible in a single query?
First one returns the difference and second one ruturns the stddev and avg:
--difference
WITH rn as(
SELECT timestamp , row_number()over() rown
FROM datapoints order by timestamp
)
SELECT ta.rown, tb.rown,tb.timestamp - ta.timestamp
FROM rn as ta,rn as tb
WHERE ta.rown=tb.rown+1 ;
--avg, stddev
WITH rn as(
SELECT timestamp , row_number()over() rown
FROM datapoints
ORDER BY timestamp
)
SELECT stddev(tb.timestamp - ta.timestamp), avg(tb.timestamp - ta.timestamp)
FROM rn as ta,rn as tb
WHERE ta.rown=tb.rown+1 ;
Unless I misunderstood or oversimplified your question
something like this might be helpful.
select t2.timestamp - t1.timestamp
from
TableName t1
join TableName t2 on
(
t1.timestamp < t2.timestamp
and
(
not exists select null from TableName tMid
where
tMid.timestamp > t1.timestamp and tMid.timestamp < t2.timestamp
)
)
I doubt this is the most efficient thing to do but you mentioned you want it done with one single query.
Just giving you an idea.
If your IDs are consecutive, you could do the join much simpler
(on t1.ID = t2.ID-1 or something similar).
Then also you need to see how to also include the last/first difference
(maybe you try an outer join). I think my query misses that one.
Never mind, seems I probably misunderstood your question.
This seems useful for your case.
SQL: Show average and min/max within standard deviations

select 10 rows with lowest time difference in sql

I'm using sql-server 2005
Hi, i have Users table with userID and registrationDate. I want to select shortest period of time between two registrationDates when first date is x and other row is x+10 rows. I don't mind cursor because i will run this query once in a while.
I will explain again, i need shortest period of time between 10 users registrations to get an idea what a high border of registrations per certain time can be.
thanks
Try this query if you are using SQL Server 2005 or newer:
WITH T1 AS (
SELECT
userID,
registrationDate,
ROW_NUMBER() OVER (ORDER BY registrationDate) AS rn
FROM Users
), T3 AS (
SELECT
T1.registrationDate AS interval_start,
T2.registrationDate AS interval_end,
T1.registrationDate - T2.registrationDate AS diff
FROM T1
JOIN T1 T2
ON T1.rn = T2.rn + 5
)
SELECT TOP 1 interval_start, interval_end
FROM T3
ORDER BY diff