interval overlapping in tsql - tsql

i need to get splited intervals and the number of overlapping intervals, eg
basedata:
interval A: startTime 08:00, endTime 12:00
interval B: startTime 09:00, endTime 12:00
interval C: startTime 12:00, endTime 16:00
interval D: startTime 13:00, endTime 14:00
now i have a separate interval from 10:00 to 15:00 and have to determine what intervals are intersected at first. result should be something like:
1: 10:00 - 12:00 ( intersecting with interval A )
2: 10:00 - 12:00 ( intersecting with interval B )
3: 12:00 - 15:00 ( intersecting with interval C )
4: 13:00 - 14:00 ( intersecting with interval D )
this part works fine, the following causes the trouble:
i need some kind of weighting for parallel intervals. this also means, that it can occur that an interval-intersection must be splitted n times, if it's ( partly ) intersected by another one.
in the upper example the expecting result would be:
1: 10:00 - 12:00 -> weightage: 50%
2: 10:00 - 12:00 -> weightage: 50%
3.1: 12:00 - 13:00 -> weightage: 1oo%
3.2: 13:00 - 14:00 -> weightage: 50%
3.3: 14:00 - 15:00 -> weightage: 50%
4: 13:00 - 14:00 -< weightage: 100%
the splitting of interval 3 is caused by the intersecting with interval 4 between 13:00 and 14:00.
sql-server is ms-sql 2008.
thanks for help in advance!

If I understand what you're trying to do correctly, shouldn't your expected result be
1: 10:00 - 12:00 -> weightage: 50%
2: 10:00 - 12:00 -> weightage: 50%
3.1: 12:00 - 13:00 -> weightage: 1oo%
3.2: 13:00 - 14:00 -> weightage: 50%
3.3: 14:00 - 15:00 -> weightage: 50%
4: 13:00 - 14:00 -< weightage: 50%
since 13:00-14:00 is used twice?

Related

How to create one to many records in postgres?

I have a table that I am trying to populate multiple values based on Did.
Original table:
Sid
Did
Time1s
Time1e
Time2s
Time2e
Time3s
Time3e
U1
1
8:00
8:30
8:40
9:20
10:00
10:30
U2
2
9:00
9:30
10:00
10:30
11:00
11:30
And I would need like the below
Output :
Sid
Did
Time1s
Time1e
U1
1
8:00
8:30
U1
1
8:40
9:20
U1
1
10:00
10:30
U2
2
9:00
9:30
U2
2
10:00
10:30
U2
2
11:00
11:30
How would I do this in postgres? Thanks in advance.
You can do it using this approach
SELECT t.sid,
CASE v.i WHEN 1 THEN "Time1s"
WHEN 2 THEN "Time2s"
WHEN 3 THEN "Time3s"
END AS Time1s,
...
FROM your_table t
CROSS JOIN (VALUES (1), (2), (3)) v(i)

How to split and aggregate days into different month

db fiddle
run select *, return_date - pickup_date as total from order_history order by id; return the following result:
id pickup_date return_date date_ranges total
1 2020-03-01 2020-03-12 [2020-03-01,2020-04-01) 11
2 2020-03-01 2020-03-22 [2020-03-01,2020-04-01) 21
3 2020-03-11 2020-03-22 [2020-03-01,2020-04-01) 11
4 2020-02-11 2020-03-22 [2020-02-01,2020-03-01) 40
5 2020-01-01 2020-01-22 [2020-01-01,2020-02-01) 21
6 2020-01-01 2020-04-22 [2020-01-01,2020-02-01) 112
for example:
--id=6. total = 112. 112 = 22+ 31 + 29 + 30
--therefore toal should split: jan2020: 30, feb2020:29, march2020: 31, 2020apr:22.
first split then aggregate. aggregate based over range min(pickup_date), max(return_date) then tochar cast to 'YYYY-MM'; In this case the aggregate should group by 2020-01, 2020-02, 2020-03,2020-04.
but if pickup_date in the same month with return_date then compuate return_date - pickup_date then aggregate/sum the result, group by to_char(pickup_date,'YYYY-MM')
step-by-step demo: db<>fiddle
Not quite perfect, but a sketch:
SELECT
id,
ARRAY_AGG( -- 4
LEAST(return_date, gs + interval '1 month - 1 day') -- 2
- GREATEST(pickup_date, gs) -- 3
+ interval '1 day'
)
FROM order_history,
generate_series( -- 1
date_trunc('month', pickup_date),
date_trunc('month', return_date),
interval '1 month'
) gs
GROUP BY id
Generate a set of months that are included in the given date range
a) Calculate the last day of the month (first of a month + 1 month is first of the next month; minus 1 day is last of the current month). This is the max day for returning in this month. b) if it happened earlier, then take the earler day (LEAST())
Same for pickup day. Afterwards calculate the difference of the days kept in one month.
Aggregate the values for one month.
Open questions / Potential enhancements:
You said:
jan2020: 30, feb2020:29, march2020: 31, 2020apr:22.
Why is JAN given with 30 days? On the other hand you count APR 22 days (1st - 22nd). Following the logic, JAN should be 31, shouldn't it?
If you don't want to count the very first day, then you can change (3.) to
GREATEST(pickup_date + interval '1 day', gs)
There's a problem with day saving time in March (30 days, 23 hours instead of 31 days). This can be faced by some rounding, for example.

Fetch last available value if there is NULL

I have a table that is essentially a purchases table that has purchase prices. When a purchase is made, it is recorded at an hour. Like in the table, ABC-123 was purchased on 2022-1-20 at 12:00. I want the NULL values to show 20 as long as a new purchase price is not punched in. Same for the other id_code.
id_code
hour
purchase_price
ABC-123
2022-1-20 12:00
20
ABC-123
2022-1-20 13:00
NULL
ABC-123
2022-1-20 14:00
NULL
BCD-123
2022-1-20 12:00
35
BCD-123
2022-1-20 13:00
36
BCD-123
2022-1-20 14:00
NULL
The output table will look like this:
It will replace the NULLs with the previously available price for its particular id_code.
id_code
hour
purchase_price
ABC-123
2022-1-20 12:00
20
ABC-123
2022-1-20 13:00
20
ABC-123
2022-1-20 14:00
20
BCD-123
2022-1-20 12:00
35
BCD-123
2022-1-20 13:00
36
BCD-123
2022-1-20 14:00
36
I did find a similar question here but that seems to not work because my IDs are not incremental integers I think.
You can create a view with an aggregate function. Try this :
CREATE VIEW test_view AS
( SELECT id_code
, hour
, (array_agg(purchase_price) FILTER (WHERE purchase_price IS NOT NULL) OVER (PARTITION BY id_code ORDER BY hour DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING))[1]
FROM test
)
Result :
id_code hour array_agg
ABC-123 2022-01-20 12:00:00 20
ABC-123 2022-01-20 13:00:00 20
ABC-123 2022-01-20 14:00:00 20
BCD-123 2022-01-20 12:00:00 35
BCD-123 2022-01-20 13:00:00 36
BCD-123 2022-01-20 14:00:00 36
see the demo in dbfiddle.

how to create 30 minutes time slots in flutter/dart

How to create time slots in flutter / dart?
I want to make a list of 30 minutes time slots from given start time and end time.
Example:
start time 9:00 AM
end Time is 10:00 PM
list will be
List<String> timeSlots = ['9:30 AM','10:00 AM','10:30 AM','11:00 AM'....]
Is there any library to solve this problem?
You can create this with a generator, though the syntax is a little ugly since the TimeOfDay class added by Flutter isn't very powerful:
Iterable<TimeOfDay> getTimes(TimeOfDay startTime, TimeOfDay endTime, Duration step) sync* {
var hour = startTime.hour;
var minute = startTime.minute;
do {
yield TimeOfDay(hour: hour, minute: minute);
minute += step.inMinutes;
while (minute >= 60) {
minute -= 60;
hour++;
}
} while (hour < endTime.hour ||
(hour == endTime.hour && minute <= endTime.minute));
}
Usage:
final startTime = TimeOfDay(hour: 9, minute: 0);
final endTime = TimeOfDay(hour: 22, minute: 0);
final step = Duration(minutes: 30);
final times = getTimes(startTime, endTime, step)
.map((tod) => tod.format(context))
.toList();
print(times);
// Results:
// [9:00 AM, 9:30 AM, 10:00 AM, 10:30 AM, 11:00 AM, 11:30 AM, 12:00 PM, 12:30 PM, 1:00 PM, 1:30 PM, 2:00 PM, 2:30 PM, 3:00 PM, 3:30 PM, 4:00 PM, 4:30 PM, 5:00 PM, 5:30 PM, 6:00 PM, 6:30 PM, 7:00 PM, 7:30 PM, 8:00 PM, 8:30 PM, 9:00 PM, 9:30 PM, 10:00 PM]
Create a list with length : List.generate
List<String>.generate(3, (int index) => "time ${index + 1}");
// ["time 1", "time 2", "time 3"]

generate_series for every hour in hh24:mi:ss format

i have a generate series of every minute for the whole 24 hours. how about a generate _series showing every hour only in hh24:mi:ss and hh24:mi format.
result should be
00:00
01:00
02:00
:
:
23:00
This query:
SELECT to_char(generate_series(0, 23) * interval '1 hour' + '2019-01-01 00:00:00'::timestamp, 'HH24:MI')
will return:
00:00
01:00
02:00
03:00
...
23:00
Just modify the format string for what you desire.