My Query for on oracle DB is:
SELECT NBR, START_TIME,END_TIME, BYTES_DATA
FROM TABLE_NAME Partition (P201607)
WHERE BYTES_DATA <> 0 AND NBR LIKE '%29320319%'
and results in:
NBR START_TIME END_TIME BYTES_DATA
1029320319 2016-07-01 00:15:51 2016-07-01 00:22:44 158014048
1029320319 2016-07-01 00:22:51 2016-07-01 01:22:51 616324863
1029320319 2016-07-01 01:22:51 2016-07-01 01:55:15 431354240
1029320319 2016-07-01 01:55:22 2016-07-01 02:53:45 1040869155
1029320319 2016-07-01 02:53:52 2016-07-01 03:53:52 40615861
1029320319 2016-07-04 07:22:05 2016-07-04 07:22:05 4911
1029320319 2016-07-05 06:42:56 2016-07-05 07:42:56 58271774
1029320319 2016-07-05 07:42:56 2016-07-05 07:42:56 173
1029320319 2016-07-08 07:47:01 2016-07-08 07:47:01 105995
But I would like to filter these output based on Time. How can I get all records during this month(07) or last 7 days where the start_time and end_time is between 06:30:00 and 07:59:59?
Using either to_date or to_char you can reformat the date/time field to match the required criteria, e.g.
This example will show all entries where the month in start or end time is same as the current month:
SELECT NBR, START_TIME,END_TIME, BYTES_DATA
FROM TABLE_NAME Partition (P201607)
WHERE BYTES_DATA <> 0 AND NBR LIKE '%29320319%'
AND ( (TO_DATE(START_TIME, 'mm') = TO_DATE(SYSDATE, 'mm') OR
(TO_DATE(END_TIME, 'mm') = TO_DATE(SYSDATE, 'mm'))
Change the matching criteria for last 7 days, e.g.
The trunc keyword removes the timestamp from a date/time value:
AND ( (TO_DATE(START_TIME, 'yyyy/mm/dd') >= (TRUNC(SYSDATE) - INTERVAL '7' days) OR
(TO_DATE(END_TIME, 'yyyy/mm/dd') >= (TRUNC(SYSDATE) - INTERVAL '7' days))
Change the format mask within the to_date to specify times, e.g.
This addition will filter for entries where start or end times are between 06:30:00 and 07:59:59 :
AND ( (TO_DATE(START_TIME,'hh24:mi:ss') BETWEEN
TO_DATE('06:30:00','hh24:mi:ss') AND
TO_DATE('07:59:59','hh24:mi:ss') ) OR
(TO_DATE(END_TIME,'hh24:mi:ss') BETWEEN
TO_DATE('06:30:00','hh24:mi:ss') AND
TO_DATE('07:59:59','hh24:mi:ss') )
I like TechOnTheNet for descriptions/syntax of this and other Oracle functions. See link for full list of available format parameters.
Related
I want to see the previous quarter's max month(as a new column) value in the current quarter using a big query.
When in Q1 2022 it should display Q4 December 2021 as a new column
When in Q2 2022 it should display Q1 March 2022 (in this case 60000)
When in Q3 2022 it should display Q2 June 2022 (in this case 40000)
My data is like below
date Sales
2022-09-01 10000
2022-08-02 20000
2022-07-01 30000
2022-06-01 40000
2022-05-01 30000
2022-04-01 50000
2022-03-01 60000
2022-02-01 10000
2022-01-01 89090
Output
your given result table fits not the task: previous quarter's max month.
Here several outputs. Do you want the maximum of the last months, or the values from three month ago? Both columns are included here.
The formula of the 1st month of quarter can be edit to the last month by changing the 1 to -1. As You want zero values for all other months, you need to multiply this with the other column.
Window function do the job. But for each month there must be one row. This is filled up with the all_months table.
with tbl as
(
Select date("2022-09-01") as dates, 10000 money
union all select date("2022-08-02"), 20000
union all select date("2022-07-01"), 30000
union all select date("2022-06-01"), 40000
union all select date("2022-05-01"), 30000
union all select date("2022-04-01"), 50000
union all select date("2022-03-01"), 60000
union all select date("2022-02-01"), 10000
union all select date("2022-01-01"), 89090
),
all_months as
(select dates,0 from (Select max(dates) A, min(dates) B from tbl), unnest(generate_date_array(A,B,interval 1 month)) dates)
select *,
if( date_trunc(dates,quarter)= date_trunc(date_sub(dates,interval 1 month),quarter),0,1) as first_month_of_quarter,
lag(money_max_this_quarter) over (order by dates) as money_max_last_quarter,
lag(money,3) over (order by dates) as money_three_months_ago,
from
(
select * ,
max(money) over (partition by date_trunc(dates,quarter ) ) as money_max_this_quarter
from
(
Select dates,sum(money) as money from tbl group by 1
union all select * from all_months
)
)
order by 1 desc
I have the dataset:
The problem is that the records are added only if an event happened, e.g. for the row with id 13897, the record was updated on 4/18/2020 and then on 5/1/2020 - the status was changed. What I need is the status of each record at the end of every month.
I was thinking about the below logic:
generate the series of dates from the min(date) till now - T1
get distinct id from the dataset - T2
do cross join between two above tables so that we get a new row for every row in the second table - T3
extract the dataset with all required fields - T4
merge T3 and T4 by concatenate(date and id) - T5
sort T5 by id and d asc - T5
fill-down all the fields grouped by id - T5
generate the series of dates from min(date) till now with the interval of one month and get the last day of each month - T6
merge T5 and T6 by date - right join so that we get only rows with the date = end of month
I am on step 6.
SELECT *
FROM (SELECT d, Concat(dt, t2.id) AS cnct
FROM (SELECT d,d::date AS dt
FROM generate_series(
( SELECT min(created_at::date)
FROM new_table), CURRENT_DATE , interval '1 day') d) t1
CROSS JOIN
(SELECT DISTINCT id FROM new_table )) t2)t3
--in case if a record with the same id was updated several times throughout the day
LEFT JOIN (WITH cte AS
( SELECT id, status, created_at at time zone 'eat' at time zone 'utc' AS "created_at", updated_at::date AS date, updated_at::date, row_number() OVER (partition BY id, updated_at::date ORDER BY updated_at DESC) rnFROM new_table ))SELECT cte.*, Concat(updated_at::date, id) AS cnct
FROM cte
WHERE rn = 1) t4
ON t3.cnct = t4.cnct
I am stuck on step 7. I found fill column with last value from partition in postgresql but it is not what I need. I envision that I need to sort by a date block i.e. dates from min date to now for one id - 13894 are to be considered block 1, dates from min date to now for another id - 13897 are to be considered block 2. The next step I thought is to fill-down all fields per a block.
And another question, how do you deal with the event-based data to adapt it for the time-series?
Tried:
You can use Postgresql's DISTINCT ON feature to do this. We'll generate a series with the start of every month (you'll need to supply start and end dates here) and put the ID and the date into the DISTINCT ON so that we get only one row of new_table for each distinct ID and month pair. Then we simply filter and order to ensure that the row we're getting for each ID and month is the latest row for which the date is before the new month.
SELECT DISTINCT ON (new_table.id, month_start) *
FROM new_table, generate_series(start_date, end_date, interval '1 month') month_start
WHERE new_table.date < month_start
ORDER BY new_table.id, month_start ASC, new_table.date DESC;
(If you need your results to have the last day of the month and not the first day of the next month, you can just subtract 1 day from month_start in your select clause.)
EDIT: Running on the data you supplied, I get this:
SELECT DISTINCT ON (new_table.id, month_start) new_table.id, month_start - interval '1 day' as month_end, new_table.status
FROM new_table, generate_series('2020-05-01', '2020-06-01', interval '1 month') month_start
WHERE new_table.date < month_start
ORDER BY new_table.id, month_start ASC, new_table.date DESC;
id | month_end | status
-------+------------------------+--------
13894 | 2020-04-30 00:00:00-07 | 5
13894 | 2020-05-31 00:00:00-07 | 5
13897 | 2020-04-30 00:00:00-07 | 2
13897 | 2020-05-31 00:00:00-07 | 5
(4 rows)
I am using below query for fetching the record month wise but it give
wrong data
SELECT
(count( server_time::timestamp::date)) ,
min(server_time::timestamp::date) as "Month Date"
FROM
complaint_details_v2
WHERE
server_time between '2018/08/01' and '2018/10/30'
GROUP BY
floor((server_time::timestamp::date - '2018/08/01'::date)/30)
ORDER BY
2 ASC
Result
Count Month Date
2774 2018-08-01
5893 2018-08-31
1193 2018-09-30
But result will be
Count Month Date
2774 2018-08-01
5893 2018-09-01
1193 2018-10-01
Use date_trunc
demo:db<>fiddle
SELECT
count(*),
date_trunc('month', servertime)::date as month_date
FROM log
GROUP BY date_trunc('month', servertime)
ORDER BY 2
I'm trying to create a calculation based on days in a quarter. Problem is, I just can't find anything on how to do it that's similar to how you would do day of year.
SELECT
event_date,
day_of_quarter
FROM table_a
WHERE event_date BETWEEN '2018-10-01' AND '2019-03-31'
So in the above example for day_of_quarter, 2018-10-01 would retun 1, 2018-12-31 would return 92 and say, 2019-03-05 would return 5
Here is the SQL for this
SELECT
event_date,
(event_date - date_trunc('quarter', event_date)::date)+1 day_of_quarter
FROM table_a
WHERE event_date BETWEEN '2018-10-01' AND '2019-03-31'
just event_date - date_trunc('quarter', event_date) gives a day before, thus +1
I have an employee status history table.
I need to create one more column that should copy the min(EffectiveStartDate) on each row till the employee is rehired. I need to get the length of service of the employee where the date will be passed by UI.
How can i achieve in SQL server 2014
This answer has a few assumptions.
Assumptions
The data set is only for one Employee at a time. If it is not,
and there is another column, such as EmployeeID, then you will
want to specify that in a partition by clause inside the over
clause where my comments denote that.
That the EmployeeStatusCatalog values have the below meanings:
A: Active
L: Leave (of Absence)
I: Inactive
That a "Hire" or "Rehire" transaction is considered to happen
either at initial A status, or after an I status has ended.
Sample Data Setup
Did not include the EmployeeStatusId column, as my assumption is that it is not relevant to creating the expected outcome.
declare #employee table
(
EffectiveStartDate date not null
, EffectiveEndDate date not null
, EmployeeStatusCatalog char(1) not null
)
insert into #employee
values ('2008-02-29', '2016-05-31', 'A')
, ('2016-06-01', '2016-06-30', 'A')
, ('2016-07-01', '2016-07-30', 'L')
, ('2016-07-31', '2016-09-02', 'A')
, ('2016-09-03', '2016-10-09', 'I')
, ('2016-10-10', '2016-11-01', 'A')
, ('2016-11-02', '2016-12-02', 'L')
, ('2016-12-03', '2016-12-05', 'I')
, ('2016-12-06', '2016-12-06', 'A')
, ('2016-12-07', '2017-01-01', 'L')
, ('2017-01-02', '9999-12-31', 'A')
Answer
As you may or may not know, this is a classic gaps and islands scenario. Where each segment between Hire/Rehire dates is an island (no gaps in this example).
I used a CTE to move the I status forward one row (via LAG function), and then get the running count of the number of I rows to give each island a "ID" number.
After that, used a min function, while partitioning by the island number, to determine the minimum EffectiveStartDate for each island.
; with inactive_dts as
(
--move the I status forward one row
select e.EffectiveStartDate
, e.EffectiveEndDate
, e.EmployeeStatusCatalog
, lag(e.EmployeeStatusCatalog, 1, 'A') over (/*partion by here*/ order by e.EffectiveStartDate asc) as prev_status
from #employee as e
where 1=1
)
, active_island_nbr as
(
--get the running count of the number of I rows
select a.EffectiveStartDate
, a.EffectiveEndDate
, a.EmployeeStatusCatalog
, a.prev_status
, sum(case a.prev_status when 'I' then 1 else 0 end) over (/*partition by here*/ order by a.EffectiveStartDate asc) as ActiveIslandNbr
from inactive_dts as a
)
select min(a.EffectiveStartDate) over (partition by a.ActiveIslandNbr) as HireRehireDate
, a.EffectiveStartDate
, a.EffectiveEndDate
, a.EmployeeStatusCatalog
from active_island_nbr as a
Results
HireRehireDate EffectiveStartDate EffectiveEndDate EmployeeStatusCatalog
2008-02-29 2008-02-29 2016-05-31 A
2008-02-29 2016-06-01 2016-06-30 A
2008-02-29 2016-07-01 2016-07-30 L
2008-02-29 2016-07-31 2016-09-02 A
2008-02-29 2016-09-03 2016-10-09 I
2016-10-10 2016-10-10 2016-11-01 A
2016-10-10 2016-11-02 2016-12-02 L
2016-10-10 2016-12-03 2016-12-05 I
2016-12-06 2016-12-06 2016-12-06 A
2016-12-06 2016-12-07 2017-01-01 L
2016-12-06 2017-01-02 9999-12-31 A