I have a table that includes multiple records duplicated status values.
DEVICE STATUS CHANGE_DATE
1 1 21.11.2017 12:01
1 0 21.11.2017 13:05
1 1 21.11.2017 14:06
1 0 21.11.2017 14:26
1 1 21.11.2017 14:36
2 0 21.11.2017 15:28
2 1 21.11.2017 15:39
Device status change priodically.
First question is, I want to select by device id last status is 1.
Query result will be like this;
DEVICE STATUS CHANGE_DATE
1 1 21.11.2017 14:36
2 1 21.11.2017 15:39
The second query is about update for same result. If data comes like this:
DEVICE STATUS CHANGE_DATE
1 1 11.11.2017 12:36
1 1 21.11.2017 14:36
2 1 21.11.2017 15:39
Device 1 is an old date. And I want to update a record is older 2 days.
How can I create these oracle queries? Select and update older records.
I'm tempted to close the question as too broad. But, I'll answer the first part:
select t.*
from (select t.*,
row_number() over (partition by device order by change_date desc) as seqnum
from t
) t
where seqnum = 1;
I think the "update" should be a separate question.
Related
There is a query I need to write that will filter out multiples of the same downtime event. These records get created at the exact same time with multiple different timestealrs which I don't need. Also, in the event of multiple timestealers for a downtime event I need to make the timestealer 'NULL' instead.
Example table:
Id
TimeStealer
Start
End
Is_Downtime
Downtime_Event
1
Machine 1
2022-01-01 01:00:00
2022-01-01 01:01:00
1
Malfunction
2
Machine 2
2022-01-01 01:00:00
2022-01-01 01:01:00
1
Malfunction
3
NULL
2022-01-01 00:01:00
2022-01-01 00:59:59
0
Operating
What I need the query to return:
Id
TimeStealer
Start
End
Is_Downtime
Downtime_Event
1
NULL
2022-01-01 01:00:00
2022-01-01 01:01:00
1
Malfunction
2
NULL
2022-01-01 00:01:00
2022-01-01 00:59:59
0
Operating
Seems like this is a top 1 row of each group, but with the added logic of making a column NULL when there are multiple rows. You can achieve that by also using a windowed COUNT, and then a CASE expression in the outer SELECT to only return the value of TimeStealer when there was 1 event:
WITH CTE AS(
SELECT V.Id,
V.TimeStealer,
V.Start,
V.[End],
V.Is_Downtime,
V.Downtime_Event,
ROW_NUMBER() OVER (PARTITION BY V.Start, V.[End], V.Is_Downtime,V.Downtime_Event ORDER BY ID) AS RN,
COUNT(V.ID) OVER (PARTITION BY V.Start, V.[End], V.Is_Downtime,V.Downtime_Event) AS Events
FROM(VALUES('1','Machine 1',CONVERT(datetime2(0),'2022-01-01 01:00:00'),CONVERT(datetime2(0),'2022-01-01 01:01:00'),'1','Malfunction'),
('2','Machine 2',CONVERT(datetime2(0),'2022-01-01 01:00:00'),CONVERT(datetime2(0),'2022-01-01 01:01:00'),'1','Malfunction'),
('3','NULL',CONVERT(datetime2(0),'2022-01-01 00:01:00'),CONVERT(datetime2(0),'2022-01-01 00:59:59'),'0','Operating'))V(Id,TimeStealer,[Start],[End],Is_Downtime,Downtime_Event))
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS ID,
CASE WHEN C.Events = 1 THEN C.TimeStealer END AS TimeStealer,
C.Start,
C.[End],
C.Is_Downtime,
C.Downtime_Event
FROM CTE C
WHERE C.RN = 1;
I've got a problem with my SQL task and didn't find any answers yet.
I've got table with this sample data:
ID
Value
Date
1
1
2020-01-01
1
2
2020-03-02
1
1
2020-03-21
1
1
2020-04-14
1
3
2020-05-01
1
1
2020-08-09
1
1
2020-09-12
1
1
2020-10-12
1
3
2020-12-04
All I want to get is:
ID
Value
Date
1
1
2020-01-01
1
2
2020-03-02
1
1
2020-03-21
1
3
2020-05-01
1
1
2020-08-09
1
3
2020-12-04
Some kind of changing value history, but only if the value was changed - when value on new record is the same, get value with min date.
I tried with grouping and row_number, but got no positive results. Any ideas how to do that?
One way to articulate your logic is to say that you want to retain a record when the previous record, as ordered by the date (within a given ID), has a different value than the current record.
WITH cte AS (
SELECT *, LAG(Value) OVER (PARTITION BY ID ORDER BY Date) LagValue
FROM yourTable
)
SELECT ID, Value, Date
FROM cte
WHERE LagValue <> Value OR LagValue IS NULL
ORDER BY Date;
Demo
Device uptime time series table
There is a device monitor table recording if a device is up (STATE 1) or down for each day.
DEVICE_ID, STATE, DATE
1 0 2017-10-09
1 1 2017-10-10
1 1 2017-10-11
1 1 2017-10-12
1 0 2017-10-13
1 1 2017-10-14
1 1 2017-10-15
1 0 2017-10-16
1 1 2017-10-17
1 0 2017-10-18
...
2 0 2017-10-10
...
Question
How can I the duration of dates during which each device was up? The device 1 went up on 2017-10-10 and went down on 2017-10-13, hence it was up for 3 days (10, 11, 12). Then 2 days from 2017-10-14 to 2017-10-15.
The expected result should look like below.
DEVICE_ID, STATE, DATE
1 3 2017-10-10
1 2 2017-10-14
1 1 2017-10-17
Please advise.
This is a gaps-and-islands problem. You can solve this version with the difference of row numbers:
select device_id, min(date), max(date), count(*) as num_days
from (select t.*,
row_number() over (partition by device_id order by date) as seqnum,
row_number() over (partition by device_id, state order by date) as seqnum_2
from t
) t
where state = 1
group by device_id, (seqnum - seqnum_2), state;
Why this works is a little tricky to explain. If you stare at the results of the subquery, you will see how the difference between the two row number values defines the adjacent values that you want.
I am trying to write a sql query (in amazon redshift) that counts the number of times that customer goes from not meeting criteria to meeting criteria, so when a 1 occurs the date after a 0.
I'm stuggling to figure out the logic to do this
ID Snapshot_date Meets Criteria
55 1/1/2018 0
55 1/5/2018 1
55 1/10/2018 1
55 1/15/2018 1
55 1/20/2018 0
55 1/25/2018 1
Use lag to get the previous value,check for the conditions and count.
select id,count(*)
from (select id,snapshot_date
,lag(meets_critetria,1) over(partition by id order by snapshot_date) as prev_m_c
from tbl
) t
where prev_m_c = 0 and meets_criteria = 1
group by id
This post is really similar to my question:
SQL Server : how many days each item was in each state
but I dont have the column Revision to see wich is the previous state, and also I want to get the full time of a status, I b
....
I'm want to get how long one item has been in one status in general, my table look like this:
ID DATE STATUS
3D56B7B1-FCB3-4897-BAEB-004796E0DC8D 2016-04-05 11:30:00.000 1
3D56B7B1-FCB3-4897-BAEB-004796E0DC8D 2016-04-08 11:30:00.000 13
274C5DA9-9C38-4A54-A697-009933BB7B7F 2016-04-29 08:00:00.000 5
274C5DA9-9C38-4A54-A697-009933BB7B7F 2016-05-04 08:00:00.000 4
A70A66DC-9D9E-49BE-93CF-00F9E3E06CE2 2016-04-14 07:50:00.000 1
A70A66DC-9D9E-49BE-93CF-00F9E3E06CE2 2016-04-21 14:00:00.000 2
A70A66DC-9D9E-49BE-93CF-00F9E3E06CE2 2016-04-23 12:15:00.000 3
A70A66DC-9D9E-49BE-93CF-00F9E3E06CE2 2016-04-23 16:15:00.000 1
BF122AE1-CB39-4967-8F37-012DC55E92A7 2016-04-05 10:30:00.000 1
BF122AE1-CB39-4967-8F37-012DC55E92A7 2016-04-20 17:00:00.000 5
I want to get this
Column 1 : ID Column 2 : Status Column 3 : Time with the status
Column 3 : Time with the status
= NextDate - PreviosDate + 1
if is the last Status, is count as 1
if is more than one Status on the same day, I get the Last one (u can say that only mather the last Status of the day)
by ID, Status must be unique
I should look like this:
ID STATUS TIME
3D56B7B1-FCB3-4897-BAEB-004796E0DC8D 1 3
3D56B7B1-FCB3-4897-BAEB-004796E0DC8D 13 1
274C5DA9-9C38-4A54-A697-009933BB7B7F 5 5
274C5DA9-9C38-4A54-A697-009933BB7B7F 4 1
A70A66DC-9D9E-49BE-93CF-00F9E3E06CE2 1 8
A70A66DC-9D9E-49BE-93CF-00F9E3E06CE2 2 2
BF122AE1-CB39-4967-8F37-012DC55E92A7 1 15
BF122AE1-CB39-4967-8F37-012DC55E92A 5 1
Thanks to #ConradFrix comments, this is how works ..
WITH CTE
AS
(
SELECT
ID,
STATUS,
DATE,
LEAD(DATE, 1) over (partition by ID order by DATE) LEAD,
ISNULL(DATEDIFF(DAYOFYEAR, DATE,
LEAD(DATE, 1) over (partition by ID order by DATE)), 1) DIF_BY_LEAD
FROM TABLE_NAME
)
SELECT ID, STATUS, SUM(DIF_BY_LEAD) AS TIME_STATUS
FROM CTE GROUP BY ID, STATUS
ORDER BY ID, STATUS