select latest record for each battery using SQL with count - sql

BatteryId TimeStamp Temprature
1 2017-02-13 12:16:14.000 23
1 2016-02-13 12:13:14.000 21
1 2015-01-13 12:16:14.000 19
2 2017-02-11 12:16:14.000 22
2 2016-02-13 12:16:14.000 16
3 2017-02-13 11:16:14.000 12
3 2016-02-13 12:15:14.000 25
I have table with multiple records for each battery as above
following sql query is returning latest record for each battery
SELECT * FROM (SELECT BatteryId, Timestamp, Temperature
ROW_NUMBER() OVER(PARTITION BY BatteryId ORDER BY timestamp DESC)
AS N FROM tblBattery) AS TT WHERE N = 1
as
BatteryId TimeStamp Temprature
1 2017-02-13 12:16:14.000 23
2 2017-02-11 12:16:14.000 22
3 2017-02-13 11:16:14.000 12
How I can add Count for each BatteryId, Here is what I need
BatteryId TimeStamp Temprature Count
1 2017-02-13 12:16:14.000 23 3
2 2017-02-11 12:16:14.000 22 2
3 2017-02-13 11:16:14.000 12 2

Use the count window function.
SELECT * FROM
(SELECT BatteryId, Timestamp, Temperature,
ROW_NUMBER() OVER(PARTITION BY BatteryId ORDER BY timestamp DESC) AS N,
COUNT(*) OVER(PARTITION BY BatteryId) as Cnt
FROM tblBattery) TT
WHERE N = 1

Hoping, i understood your problem correctly.
Please check if below query can help you.
SELECT *
FROM
(SELECT BatteryId,
TIMESTAMP,
Temperature , ROW_NUMBER() OVER(PARTITION BY BatteryId ORDER BY TIMESTAMP DESC) AS N ,
COUNT(0) OVER(PARTITION BY BatteryId ) CNT
FROM tblBattery
) AS TT
WHERE N = 1;

Add a sub query before you perform the PARTITION BY
SELECT *
FROM (SELECT
BatteryId
,Timestamp
,Temperature
,Count
,ROW_NUMBER() OVER(PARTITION BY BatteryId ORDER BY timestamp DESC) AS N
FROM (SELECT *, COUNT(BatteryId) As Count FROM tblBattery GROUP BY BatteryId)) AS TT WHERE N = 1
This should solve your issue.

Related

SQLite query - Limit occurrence of value

I have a query that return this result. How can i limit the occurrence of a value from the 4th column.
19 1 _BOURC01 1
20 1 _BOURC01 3 2019-11-18
20 1 _BOURC01 3 2017-01-02
21 1 _BOURC01 6
22 1 _BOURC01 10
23 1 _BOURC01 13 2016-06-06
24 1 _BOURC01 21 2016-09-19
My Query:
SELECT "_44_SpeakerSpeech"."id" AS "id", "_44_SpeakerSpeech"."active" AS "active", "_44_SpeakerSpeech"."id_speaker" AS "id_speaker", "_44_SpeakerSpeech"."Speech" AS "Speech", "34 Program Weekend"."date" AS "date"
FROM "_44_SpeakerSpeech"
LEFT JOIN "_34_programWeekend" "34 Program Weekend" ON "_44_SpeakerSpeech"."Speech" = "34 Program Weekend"."theme_id"
WHERE "id_speaker" = "_BOURC01"
ORDER BY id_speaker, Speech, date DESC
Thanks
I think this is what you want here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY s.id, s.active, s.id_speaker, s.Speech
ORDER BY p.date DESC) rn
FROM "_44_SpeakerSpeech" s
LEFT JOIN "_34_programWeekend" p ON s.Speech = p.theme_id
WHERE s.id_speaker = '_BOURC01'
)
SELECT id, active, id_speaker, Speech, date
FROM cte
WHERE rn = 1;
This logic assumes that when two or more records all have the same columns values (excluding the date), you want to retain only the latest record.

SQL- Return rows after nth occurrence of event per user

I'm using postgreSQL 8.0 and I have a table with user_id, timestamp, and event_id.
How can I return the rows (or row) after the 4th occurrence of event_id = someID per user?
|---------------------|--------------------|------------------|
| user_id | timestamp | event_id |
|---------------------|--------------------|------------------|
| 1 | 2020-04-02 12:00 | 11 |
|---------------------|--------------------|------------------|
| 2 | 2020-04-02 13:00 | 11 |
|---------------------|--------------------|------------------|
| 2 | 2020-04-02 14:00 | 99 |
|---------------------|--------------------|------------------|
| 2 | 2020-04-02 15:00 | 11 |
|---------------------|--------------------|------------------|
| 2 | 2020-04-02 16:00 | 11 |
|---------------------|--------------------|------------------|
| 2 | 2020-04-02 17:00 | 11 |
|---------------------|--------------------|------------------|
| 2 | 2020-04-02 17:00 | 11 |
|---------------------|--------------------|------------------|
Ie if event_id = 11, I would only want the last row in the table above.
You can use window functions:
select *
from (
select t.*, row_number() over(partition by user_id, event_id order by timestamp) rn
from mytable t
) t
where rn > 4
Here is a little trick that removes the row number from the result:
select (t).*
from (
select t, row_number() over(partition by user_id, event_id order by timestamp) rn
from mytable t
) x
where rn > 4
You can use a cumulative count. This version includes the 4th occurrence:
select t.*
from (select t.*,
count(*) filter (where event_id = 11) over (partition by user_id order by timestamp) as event_11_cnt
from t
) t
where event_11_cnt >= 4;
The filter has been valid Postgres syntax for a long time, but instead, you can use:
select t.*
from (select t.*,
sum( (event_id = 11)::int ) over (partition by user_id order by timestamp) as event_11_cnt
from t
) t
where event_11_cnt >= 4;
This version does not:
where event_11_cnt > 4 or (event_11_cnt = 4 and event_id <> 11)
An alternative method:
select t.*
from t
where t.timestamp > (select t2.timestamp
from t t2
where t2.user_id = t.user_id and
t2.event_id = 11
order by t2.timestamp
limit 1 offset 3
);
sorry to be asking about such an old version of Postgres, here is an answer that worked:
WITH EventOrdered AS(
SELECT
EventTypeId
, UserId
, Timestamp
, ROW_NUMBER() OVER (PARTITION BY EventTypeId, UserId ORDER BY Timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ROW_NO
FROM Event),
FourthEvent AS (
SELECT DISTINCT
UserID
, FIRST_VALUE(TimeStamp) OVER (PARTITION BY UserId ORDER BY Timestamp) FirstFourthEventTimestamp
FROM EventOrdered
WHERE ROW_NO = 4)
SELECT e.*
FROM Event e
JOIN FourthEvent ffe
ON e.UserId = ffe.UserId
AND e.Timestamp > ffe.FirstFourthEventTimestamp
ORDER BY e.UserId, e.Timestamp

Current record with group by function

Trying to get userid recent aggregate value for session_id.
(session_id 3 has two records, recent agg value is 80.00
session_id 4 has four records, recent agg value is 95.00
session_id 6 has three records, recent agg value is 72.00
Table:session_agg
id session_id userid agg date
-- ---------- ------ ----- -------
1 3 11 60.00 1573561586
4 3 11 80.00 1573561586
6 4 11 35.00 1573561749
7 4 11 50.00 1573561751
8 4 11 70.00 1573561912
10 4 11 95.00 1573561921
11 6 14 40.00 1573561945
12 6 14 67.00 1573561967
13 6 14 72.00 1573561978
select id, session_id, userid, agg, date from session_agg
WHERE date IN (select MAX(date) from session_agg GROUP BY session_id) AND
userid = 11
If you want to stick with your current approach, then you need to correlate the session_id in the subquery which checks for the max date for each session:
SELECT id, session_id, userid, add, date
FROM session_agg sa1
WHERE
date = (SELECT MAX(date) FROM session_agg sa2 WHERE sa2.session_id = sa1.session_id) AND
userid = 11;
But, if your version of SQL supports analytic functions, ROW_NUMBER is an easier way to do this:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY session_id ORDER BY date DESC) rn
FROM session_agg
)
SELECT id, session_id, userid, add, date
FROM cte
WHERE rn = 1;

To subtract a previous row value in SQL Server 2012

This is SQL Query
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) [Sno],
_Date,
SUM(Payment) Payment
FROM
DailyPaymentSummary
GROUP BY
_Date
ORDER BY
_Date
This returns output like this
Sno _Date Payment
---------------------------
1 2017-02-02 46745.80
2 2017-02-03 100101.03
3 2017-02-06 140436.17
4 2017-02-07 159251.87
5 2017-02-08 258807.51
6 2017-02-09 510986.79
7 2017-02-10 557399.09
8 2017-02-13 751405.89
9 2017-02-14 900914.45
How can I get the additional column like below
Sno _Date Payment Diff
--------------------------------------
1 02/02/2017 46745.80 46745.80
2 02/03/2017 100101.03 53355.23
3 02/06/2017 140436.17 40335.14
4 02/07/2017 159251.87 18815.70
5 02/08/2017 258807.51 99555.64
6 02/09/2017 510986.79 252179.28
7 02/10/2017 557399.09 46412.30
8 02/13/2017 751405.89 194006.80
9 02/14/2017 900914.45 149508.56
I have tried the following query but not able to solve the error
WITH cte AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) [Sno],
_Date,
SUM(Payment) Payment
FROM
DailyPaymentSummary
GROUP BY
_Date
ORDER BY
_Date
)
SELECT
t.Payment,
t.Payment - COALESCE(tprev.col, 0) AS diff
FROM
DailyPaymentSummary t
LEFT OUTER JOIN
t tprev ON t.seqnum = tprev.seqnum + 1;
Can anyone help me?
Use a order by with column(s) to get consistent results.
Use lag function to get data from previous row and do the subtraction like this:
with t
as (
select ROW_NUMBER() over (order by _date) [Sno],
_Date,
sum(Payment) Payment
from DailyPaymentSummary
group by _date
)
select *,
Payment - lag(Payment, 1, 0) over (order by [Sno]) diff
from t;
You can use lag() to get previous row values
coalesce(lag(sum_payment_col) OVER (ORDER BY (SELECT 1)),0)

window function in redshift

I have some data that looks like this:
CustID EventID TimeStamp
1 17 1/1/15 13:23
1 17 1/1/15 14:32
1 13 1/1/25 14:54
1 13 1/3/15 1:34
1 17 1/5/15 2:54
1 1 1/5/15 3:00
2 17 2/5/15 9:12
2 17 2/5/15 9:18
2 1 2/5/15 10:02
2 13 2/8/15 7:43
2 13 2/8/15 7:50
2 1 2/8/15 8:00
I'm trying to use the row_number function to get it to look like this:
CustID EventID TimeStamp SeqNum
1 17 1/1/15 13:23 1
1 17 1/1/15 14:32 1
1 13 1/1/25 14:54 2
1 13 1/3/15 1:34 2
1 17 1/5/15 2:54 3
1 1 1/5/15 3:00 4
2 17 2/5/15 9:12 1
2 17 2/5/15 9:18 1
2 1 2/5/15 10:02 2
2 13 2/8/15 7:43 3
2 13 2/8/15 7:50 3
2 1 2/8/15 8:00 4
I tried this:
row_number () over
(partition by custID, EventID
order by custID, TimeStamp asc) SeqNum]
but got this back:
CustID EventID TimeStamp SeqNum
1 17 1/1/15 13:23 1
1 17 1/1/15 14:32 2
1 13 1/1/25 14:54 3
1 13 1/3/15 1:34 4
1 17 1/5/15 2:54 5
1 1 1/5/15 3:00 6
2 17 2/5/15 9:12 1
2 17 2/5/15 9:18 2
2 1 2/5/15 10:02 3
2 13 2/8/15 7:43 4
2 13 2/8/15 7:50 5
2 1 2/8/15 8:00 6
how can I get it to sequence based on the change in the EventID?
This is tricky. You need a multi-step process. You need to identify the groups (a difference of row_number() works for this). Then, assign an increasing constant to each group. And then use dense_rank():
select sd.*, dense_rank() over (partition by custid order by mints) as seqnum
from (select sd.*,
min(timestamp) over (partition by custid, eventid, grp) as mints
from (select sd.*,
(row_number() over (partition by custid order by timestamp) -
row_number() over (partition by custid, eventid order by timestamp)
) as grp
from somedata sd
) sd
) sd;
Another method is to use lag() and a cumulative sum:
select sd.*,
sum(case when prev_eventid is null or prev_eventid <> eventid
then 1 else 0 end) over (partition by custid order by timestamp
) as seqnum
from (select sd.*,
lag(eventid) over (partition by custid order by timestamp) as prev_eventid
from somedata sd
) sd;
EDIT:
The last time I used Amazon Redshift it didn't have row_number(). You can do:
select sd.*, dense_rank() over (partition by custid order by mints) as seqnum
from (select sd.*,
min(timestamp) over (partition by custid, eventid, grp) as mints
from (select sd.*,
(row_number() over (partition by custid order by timestamp rows between unbounded preceding and current row) -
row_number() over (partition by custid, eventid order by timestamp rows between unbounded preceding and current row)
) as grp
from somedata sd
) sd
) sd;
Try this code block:
WITH by_day
AS (SELECT
*,
ts::date AS login_day
FROM table_name)
SELECT
*,
login_day,
FIRST_VALUE(login_day) OVER (PARTITION BY userid ORDER BY login_day , userid rows unbounded preceding) AS first_day
FROM by_day