How to get min date of every month for six months? - sql

I have data like this.
Process_date SEQ_No
------------- ---------
16-MAR-13 733
09-MAR-13 732
02-MAR-13 731
24-FEB-13 730
16-FEB-13 728
09-FEB-13 727
02-FEB-13 726
26-JAN-13 725
21-JAN-13 724
12-JAN-13 723
05-JAN-13 722
29-DEC-12 721
24-DEC-12 720
15-DEC-12 719
08-DEC-12 718
03-DEC-12 717
22-NOV-12 716
17-NOV-12 715
10-NOV-12 714
03-NOV-12 713
29-OCT-12 712
23-OCT-12 711
13-OCT-12 710
05-OCT-12 709
28-SEP-12 708
22-SEP-12 707
15-SEP-12 706
08-SEP-12 705
01-SEP-12 704
Every month admin will refresh actual data table and automatically this above table will update with unique seq_no and process_date.
I need to extarct min date of everymonth(First refresh of last 6 months - excluding currrent month) and also seq_no related to that month so using joins(using seq_no - that is available in main table) i can combine actual data.
I need result like:
02-MAR-13 731 ( I don't need MAR as it should not take current month data)
so i need final result like below:
02-FEB-13 726
05-JAN-13 722
08-DEC-12 718
03-NOV-12 713
05-OCT-12 709
01-SEP-12 704
--sorry for asking direct quetion like this. I am not sure how to do that. thats the reason i have not prepared/posted any query.

select Process_date, SEQ_No
from (select Process_date, SEQ_No,
row_number() over (partition by trunc(process_date, 'mm') order by process_date) rn
from yourtab
where Process_date < trunc(sysdate, 'mm'))
where rn = 1;
will do that
fiddle example: http://sqlfiddle.com/#!4/a5452/1

I didn't understood how seq_no is in another table...
But using the input data:
select
min(process_date),
min(seq_no) keep (dense_rank first order by process_date)
from
your_table
where
process_date between add_months(trunc(sysdate,'MM'),-7)
and last_day(add_months(sysdate, -1))
group by
trunc(process_date,'MM');

Try:
SELECT seq_no,process_date FROM my_table
WHERE process_date IN (SELECT min(process_date)
FROM my_table
GROUP BY TRUNC(process_date,'MM'))

Related

Summing column that is grouped - SQL

I have a query:
SELECT
date,
COUNT(o.row_number)FILTER (WHERE o.row_number > 1 AND date_ddr IS NOT NULL AND telephone_number <> 'Anonymous' ) repeat_calls_24h
(
SELECT
telephone_number,
date_ddr,
ROW_NUMBER() OVER(PARTITION BY ddr.telephone_number ORDER BY ddr.date) row_number,
FROM
table_a
)o
GROUP BY 1
Generating the following table:
date
Repeat calls_24h
17/09/2022
182
18/09/2022
381
19/09/2022
81
20/09/2022
24
21/09/2022
91
22/09/2022
110
23/09/2022
231
What can I add to my query to provide a sum of the previous three days as below?:
date
Repeat calls_24h
Repeat Calls 3d
17/09/2022
182
18/09/2022
381
19/09/2022
81
644
20/09/2022
24
486
21/09/2022
91
196
22/09/2022
110
225
23/09/2022
231
432
Thanks
We can do it using lag.
select "date"
,"Repeat calls_24h"
,"Repeat calls_24h" + lag("Repeat calls_24h") over(order by "date") + lag("Repeat calls_24h", 2) over(order by "date") as "Repeat Calls 3d"
from t
date
Repeat calls_24h
Repeat Calls 3d
2022-09-17
182
null
2022-09-18
381
null
2022-09-19
81
644
2022-09-20
24
486
2022-09-21
91
196
2022-09-22
110
225
2022-09-23
231
432
Fiddle

PostgreSQL: How to show personal bests by comparing to previous runs

I'm looking to create the "fastest_run_time" column in PostgreSQL by looking at what the "current" personal best is as of the month of that row. So for example:
In 2016-07 my personal best was 762, it was beaten by a 720 in 2016-08
Since the run on 2016-09 of 745 isn't an improvement on 720, the fastest_run_time should stay as 720
It's only updated again when it is beaten with a 691 in 2016-12.
I've tried doing some partitioning and max/mins and have got it into this format but can't really see where to go from here
if the partition by syntax is supported:
select mt.*,
min(run_time) over
(partition by run_type
order by period
rows between unbounded preceding and current row) as fastest_run_time
from mytbl mt
Just a subquery:
select run_type, to_char(period, 'YYYY-MM'), run_time, (
select min(rs.run_time) from run rs
where rs.period <= run.period
) fastest_run_time from run;
Demo with schema.
Result:
run_type
to_char
run_time
fastest_run_time
A
2021-05
A
2021-06
762
762
A
2021-07
762
762
A
2021-08
720
720
A
2021-09
745
720
A
2021-10
745
720
A
2021-11
745
720
A
2021-12
691
691

Select a column from a different row

so I have the following table on AWS Redshift
node_id power_source timestamp
----------------------------------------------
108 LINE 2019-09-10 09:15:30
108 BATT 2019-09-10 10:20:15
108 LINE 2019-09-10 13:45:00
108 LINE 2019-09-11 06:00:15
108 BATT 2019-09-12 05:50:15
108 BATT 2019-09-12 12:15:15
108 LINE 2019-09-12 18:45:15
108 LINE 2019-09-13 09:20:15
108 BATT 2019-09-14 11:20:15
108 BATT 2019-09-14 13:30:15
108 BATT 2019-09-14 15:30:15
108 LINE 2019-09-14 16:48:36
108 LINE 2019-09-15 09:20:15
I am trying to figure out how long (cumulative) the node's power_source is on 'BATT'. I am thinking that I could do a datediff on the timestamps, but I would need to get the timestamp of the first 'LINE' row after the 'BATT' row (based on ts). Not really sure how to get that value though. Once I have that, then I could just SUM() the datediff.
Edit:
Here is the expected result
node_id power_source timestamp ts_line_power ts_diff(in mins)
-----------------------------------------------------------------------------------------
108 BATT 2019-09-10 10:20:15 2019-09-10 13:45:00 205
108 BATT 2019-09-12 05:50:15 2019-09-12 18:45:15 785
108 BATT 2019-09-14 11:20:15 2019-09-14 16:48:36 328
Any help/assistance would be appreciated
If I understand correctly, you can use lead():
select node_id,
sum(datediff(minute, timestamp, next_ts)) as diff_in_minutes
from (select t.*,
lead(timestamp) over (partition by node_id order by timestamp) as next_ts
from t
) t
where power_source = 'BATT'
group by node_id;
This gets the timestamp after the BATT record and uses that to define the end time.
EDIT:
The above is overall for all "BATT"s. You have a group-and-islands problem. For that, you can assign a group by counting the number of non-BATT records greater than each row. This keeps the next record in the group.
This is all window functions and aggregation:
select node_id, min(timestamp), max(timestamp),
sum(datediff(minute, min(timestamp), max(timestamp))) as diff_in_minutes
from (select t.*,
sum( (power_source = 'LINE')::int ) over (partition by node_id order by timestamp desc) as grp
from t
) t
group by node_id, grp
having sum( (power_source = 'BATT')::int) > 0; -- only include rows that have at least one BATT
Note that this assumes that only "LINE" and "BATT" are valid values for the power source.

SQL order dates sequentially by year

I have a SQL view that produces the following list of Mondays in a specific date range as shown below:
Date Number
16/12/2013 208
23/12/2013 190
30/12/2013 187
15/12/2014 203
22/12/2014 190
29/12/2014 153
14/12/2015 225
21/12/2015 217
28/12/2015 223
Is it possible to order them by the first of each year then the second then the third etc. to give me the results as shown below:
Date Number
16/12/2013 208
15/12/2014 203
14/12/2015 225
23/12/2013 190
22/12/2014 190
21/12/2015 217
30/12/2013 187
29/12/2014 153
28/12/2015 223
Thank you in advance for any help or advice.
I think you should be able to get what you want by using the row_number() over a partition on the year, for example:
Select [Date], [Number],
Row_Number() over (PARTITION BY Year([DATE] order by [DATE]) as WEEK_IN_YR
from [table]
order by WEEK_IN_YR, [Date]
https://msdn.microsoft.com/en-gb/library/ms186734.aspx

Calculating difference from previous record

May I ask for your help with the following please ?
I am trying to calculate a change from one record to the next in my results. It will probably help if I show you my current query and results ...
SELECT A.AuditDate, COUNT(A.NickName) as [TAccounts],
SUM(IIF((A.CurrGBP > 100 OR A.CurrUSD > 100), 1, 0)) as [Funded]
FROM Audits A
GROUP BY A.AuditDate;
The query gives me these results ...
AuditDate D/M/Y TAccounts Funded
--------------------------------------------
30/12/2011 506 285
04/01/2012 514 287
05/01/2012 514 288
06/01/2012 516 288
09/01/2012 520 289
10/01/2012 522 289
11/01/2012 523 290
12/01/2012 524 290
13/01/2012 526 291
17/01/2012 531 292
18/01/2012 532 292
19/01/2012 533 293
20/01/2012 537 295
Ideally, the results I would like to get, would be similar to the following ...
AuditDate D/M/Y TAccounts TChange Funded FChange
------------------------------------------------------------------------
30/12/2011 506 0 285 0
04/01/2012 514 8 287 2
05/01/2012 514 0 288 1
06/01/2012 516 2 288 0
09/01/2012 520 4 289 1
10/01/2012 522 2 289 0
11/01/2012 523 1 290 1
12/01/2012 524 1 290 0
13/01/2012 526 2 291 1
17/01/2012 531 5 292 1
18/01/2012 532 1 292 0
19/01/2012 533 1 293 1
20/01/2012 537 4 295 2
Looking at the row for '17/01/2012', 'TChange' has a value of 5 as the 'TAccounts' has increased from previous 526 to 531. And the 'FChange' would be based on the 'Funded' field. I guess something to be aware of is the fact that the previous row to this example, is dated '13/01/2012'. What I mean is, there are some days where I have no data (for example over weekends).
I think I need to use a SubQuery but I am really struggling to figure out where to start. Could you show me how to get the results I need please ?
I am using MS Access 2010
Many thanks for your time.
Johnny.
Here is one approach you could try...
SELECT B.AuditDate,B.TAccounts,
B.TAccount -
(SELECT Count(NickName) FROM Audits WHERE AuditDate=B.PrevAuditDate) as TChange,
B.Funded -
(SELECT Count(*) FROM Audits WHERE AuditDate=B.PrevAuditDate AND (CurrGBP > 100 OR CurrUSD > 100)) as FChange
FROM (
SELECT A.AuditDate,
(SELECT Count(NickName) FROM Audits WHERE AuditDate=A.AuditDate) as TAccounts,
(SELECT Count(*) FROM Audits WHERE (CurrGBP > 100 OR CurrUSD > 100)) as Funded,
(SELECT Max(AuditDate) FROM Audits WHERE AuditDate<A.AuditDate) as PrevAuditDate
FROM
(SELECT DISTINCT AuditDate FROM Audits) AS A) AS B
Instead of using a Group By I've used subquerys to get both TAccounts and Funded, as well as the Previous Audit Date, which is then used on the main SELECT statement to get TAccounts and Funded again but this time for the previous date, so that any required calculation can be done against them.
But I would imagine this may be slow to process
It's a shame MS never made this type of thing simple in Access, how many rows are you working with on your report?
If it's under 65K then I would suggest dumping the data on to an Excel spreadsheet and using a simple formula to calculate the different between rows.
You can try something like the following (sql is untested and will require some changes)
SELECT
A.AuditDate,
A.TAccounts,
A.TAccounts - B.TAccounts AS TChange,
A.Funded,
A.Funded - B.Funded AS FChange
FROM
( SELECT
ROW_NUMBER() OVER (ORDER BY AuditDate DESC) AS ROW,
AuditDate,
COUNT(NickName) as [TAccounts],
SUM(IIF((CurrGBP > 100 OR CurrUSD > 100), 1, 0)) as [Funded]
FROM Audits
GROUP BY AuditDate
) A
INNER JOIN
( SELECT
ROW_NUMBER() OVER (ORDER BY AuditDate DESC) AS ROW,
AuditDate,
COUNT(NickName) as [TAccounts],
SUM(IIF((CurrGBP > 100 OR CurrUSD > 100), 1, 0)) as [Funded]
FROM Audits
GROUP BY AuditDate
) B ON B.ROW = A.ROW + 1