I need to do my reporting on week on week basis but my week number should start from 1st day of month
here is my sample data:
report_date Vol
01 nov 2014 23
03 nov 2014 34
16 nov 2014 56
30 nov 2014 44
Desired output
Week no Vol
1 57
2 56
3 0
4 44
hope its clear
Thanks
Since your desired output include "zero" rows as well, and assuming you'd like this report to work across multiple months as well:
WITH sample_data AS
(SELECT DATE '2014-11-01' AS report_date, 23 AS vol FROM DUAL
UNION ALL SELECT DATE '2014-11-03', 34 FROM DUAL
UNION ALL SELECT DATE '2014-11-16', 56 FROM DUAL
UNION ALL SELECT DATE '2014-11-30', 44 FROM DUAL)
,weeks AS
(SELECT report_month
,TO_CHAR(ROWNUM) AS week_no
FROM (SELECT DISTINCT
TRUNC(report_date,'MM') AS report_month
FROM sample_data)
CONNECT BY LEVEL <= TO_NUMBER(TO_CHAR(LAST_DAY(report_month),'W')))
SELECT TO_CHAR(weeks.report_month,'Month') AS "Month"
,weeks.week_no AS "Week no"
,NVL(sum(sample_data.vol),0) AS "Vol"
FROM weeks
LEFT JOIN sample_data
ON weeks.report_month = TRUNC(report_date,'MM')
AND weeks.week_no = to_char(report_date,'W')
GROUP BY weeks.report_month, weeks.week_no ORDER BY 1,2;
We determine the number of weeks in each month of the source data by using the LAST_DAY function, and we do a hierarchical query (CONNECT BY LEVEL <= n) to generate one row for each week in each month.
The expected output should be:
Month Week no Vol
======== ======= ===
November 1 57
November 2 0
November 3 56
November 4 0
November 5 44
select to_char(report_date, 'W'), sum(vol)
from your_table
group by to_char(report_date, 'W');
W Week of month (1-5) where week 1 starts on the first day of the
month and ends on the seventh.
Related
Given the table
D V
--------------
2019-03-02, 13
2019-10-28, 12
2019-11-22, 34
2020-01-18, 21
2020-04-11, 39
I want to add a record with date 2019-12-31 replicating the last one partitioning by year
2019-03-02, 13
2019-10-28, 12
2019-11-22, 34
2019-12-31, 34 <<
2020-01-18, 21
2020-04-11, 39
2020-12-31, 39 <<
How can this be made using the Model Clause? I cannot even figure out where to start.
After reading through examples of the model clause and looking at the syntax and trying to work out how to insert rows into a model I reached the conclusion that it was not an easy task (possibly impossible) to solve your question using a MODEL clause.
However, if you want to use an appropriate method to the problem (as opposed to trying to use a MODEL clause for something it was not really designed for), you can use a recursive sub-query factoring clause:
WITH bounds (d, v, next_d) AS (
SELECT d,
v,
LEAD(d, 1, SYSDATE) OVER ( ORDER BY d )
FROM table_name
UNION ALL
SELECT ADD_MONTHS(TRUNC(d + INTERVAL '1' DAY, 'YY'), 12) - INTERVAL '1' DAY,
v,
next_d
FROM bounds
WHERE ADD_MONTHS(TRUNC(d + INTERVAL '1' DAY, 'YY'), 12) - INTERVAL '1' DAY
< next_d
)
SEARCH DEPTH FIRST BY d SET d_order
SELECT d, v
FROM bounds;
Which, for your sample data:
CREATE TABLE table_name (D, V) AS
SELECT DATE '2019-03-02', 13 FROM DUAL UNION ALL
SELECT DATE '2019-10-28', 12 FROM DUAL UNION ALL
SELECT DATE '2019-11-22', 34 FROM DUAL UNION ALL
SELECT DATE '2020-01-18', 21 FROM DUAL UNION ALL
SELECT DATE '2020-04-11', 39 FROM DUAL
Outputs:
D
V
2019-03-02 00:00:00
13
2019-10-28 00:00:00
12
2019-11-22 00:00:00
34
2019-12-31 00:00:00
34
2020-01-18 00:00:00
21
2020-04-11 00:00:00
39
2020-12-31 00:00:00
39
db<>fiddle here
I have a requirement to get the future years based on a field available for employee on the Employee table and the benefits date ,Below are the two tables and the expected output is shown below for the two employess XYZ and ABC.
Tabular Data for Employee
Employee benefit Date table
Expected Output
Case 1 --Say an Employee XYZ has value of 5 and the query is run for 03/31/2020 ,then the query would need to return as below
Input - 03/31/2020
Expected Output in rows
2020
2021
2022
2023
2024
2025+
Case 2
Say an Employee ABC has value of 10 and the query is run for 03/31/2020 ,then the query would need to return as below
Input - 03/31/2020
Expected Output in rows--
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030+
Requesting for logic to derive the years based on employee table second column and all the years above it should be shown as (year)+.
I have tried using case statements for getting years ,but would like to get someassiatcne to this dynamically based on the value field.
Thanks in Advance.
This is one option; See comments within code.
SQL> with
2 -- sample data
3 emp (employee, years) as
4 (select 'XYZ', 5 from dual union all
5 select 'ABC', 10 from dual
6 ),
7 benefit (employee, bdate) as
8 (select 'XYZ', 2021 + level - 1
9 from dual
10 connect by level <= 7
11 union all
12 select 'ABC', 2021 + level - 1
13 from dual
14 connect by level <= 13
15 )
16 select
17 b.employee,
18 case when b.bdate = x.bdate + e.years then to_char(b.bdate - 1) || '+'
19 else to_char(b.bdate)
20 end bdate
21 from benefit b join emp e on e.employee = b.employee
22 join (-- find MIN(bdate) per employee
23 select b1.employee,
24 min(b1.bdate) bdate
25 from benefit b1
26 group by b1.employee
27 ) x on x.employee = b.employee
28 and b.bdate <= (-- limit number of rows displayed
29 select min(b1.bdate) + e.years
30 from benefit b1
31 where b1.employee = b.employee
32 )
33 order by b.employee desc, b.bdate;
EMP BDATE
--- -----------------------------------------
XYZ 2021
XYZ 2022
XYZ 2023
XYZ 2024
XYZ 2025
XYZ 2025+
ABC 2021
ABC 2022
ABC 2023
ABC 2024
ABC 2025
ABC 2026
ABC 2027
ABC 2028
ABC 2029
ABC 2030
ABC 2030+
17 rows selected.
SQL>
Desired output you posted is kind of inconsistent; for XYZ, it says 2026+ which doesn't match ABC's 2030+ (should be 2031+) (or, XYZ should be 2025+ if ABC is correct). Anyway, that's easy to fix.
I have Scenario Like below and want set Indicator based on Arrange Id, Login Date.. If User login website multiple time in Calendar Year then Most recent record need to set Y else N. Also I need to set Indicator like Bottom two rows as well.. ( Means 1121221 Accessed on last year recent 12/13/2017 need to set 'Y' and if user accessed in next immediate year 1/12/2018 then 'Y' )
enter image description here
Here's one option. What does it do?
the TEST CTE are some sample rows. Note ARRANGE_ID = 999, which has dates from 2017 and 2019 (which means that there are no consecutive years, so the date in 2019 should get the indicator 'N'. You didn't say, though, what would happen if there's yet another date in 2019; would both of them get 'N', or would the max login date still get a 'Y'?
the INTER CTE uses the MAX analytic function to find the maximum login date for the year and the LAG analytic function which returns the previous login date (so that I could check whether those years are consecutive or not)
the final query uses CASE to find whether certain row satisfies conditions to make the indicator equal to 'Y'
Here you go:
SQL> with test (arrange_id, login_date) as
2 (select 234, date '2017-02-18' from dual union all
3 select 234, date '2017-04-13' from dual union all
4 select 234, date '2017-11-14' from dual union all
5 select 234, date '2018-01-14' from dual union all
6 select 234, date '2018-09-11' from dual union all
7 select 234, date '2019-04-02' from dual union all
8 select 234, date '2019-05-18' from dual union all
9 select 112, date '2017-02-23' from dual union all
10 select 112, date '2017-12-13' from dual union all
11 select 112, date '2018-01-12' from dual union all
12 select 999, date '2017-01-01' from dual union all
13 select 999, date '2017-05-25' from dual union all
14 select 999, date '2019-01-01' from dual
15 ),
16 inter as
17 (select arrange_id,
18 login_date,
19 max(login_date) over
20 (partition by arrange_id, extract (year from login_date)) maxdate,
21 lag(login_date) over (partition by arrange_id order by login_date) prev_date
22 from test
23 )
24 select arrange_id,
25 login_date,
26 case when login_date = maxdate and
27 extract(year from login_date) - extract(year from prev_date) <= 1 then 'Y'
28 else 'N'
29 end indicator
30 from inter
31 order by arrange_id, login_date;
ARRANGE_ID LOGIN_DATE I
---------- ---------- -
112 02/23/2017 N
112 12/13/2017 Y -- Y because it is MAX in 2017
112 01/12/2018 Y -- Y because it is MAX in 2018 and 2018 follows 2017
234 02/18/2017 N
234 04/13/2017 N
234 11/14/2017 Y -- Y because it is MAX in 2017
234 01/14/2018 N
234 09/11/2018 Y -- Y because it is MAX in 2018 and 2018 follows 2017
234 04/02/2019 N
234 05/18/2019 Y -- Y because it is MAX in 2019 and 2019 follows 2018
999 01/01/2017 N
999 05/25/2017 Y -- Y because it is MAX in 2017
999 01/01/2019 N -- N because it is MAX in 2019, but 2019 doesn't follow 2017
13 rows selected.
SQL>
Honestly, I don't know how simply I can describe the question on the title line instead of showing an example.
I have a hive table which contains two columns: ID and date
ID Date
31 01-01-2017
31 01-02-2017
31 01-03-2017
123 01-01-2017
123 01-01-2017
...
In this table, I would like to include another column which is hour such as below
ID Date Hour
31 01-01-2017 00
31 01-01-2017 01
31 01-01-2017 02
31 01-01-2017 03
31 01-01-2017 04
...
31 01-01-2017 23
31 01-02-2017 00
31 01-02-2017 01
...
Basically, for every row, I would like add an hour column of values from 00 to 23.
Can this be achieved using hive?
Thank you so much.
You could create a temporary table which contains entries from 0 to 23 and do a cross join with the table you have. Or you can leverage on the CTE function a CTE table with entries from 0 to 23 and then do a cross join with it.
An example:
with temp as (
select 0 hour union all
select 1 hour union all
select 2 hour union all
select 3 hour union all
select 4 hour union all
select 5 hour union all
select 6 hour union all
select 7 hour union all
select 8 hour union all
select 9 hour union all
select 10 hour union all
select 11 hour union all
select 12 hour union all
select 13 hour union all
select 14 hour union all
select 15 hour union all
select 16 hour union all
select 17 hour union all
select 18 hour union all
select 19 hour union all
select 20 hour union all
select 21 hour union all
select 22 hour union all
select 23 hour
)
select * from table join temp
You can also insert the result into a table to persist the result. Hope it helps
In WORK_TIME column in my database table (EMP_WORKS), i have records as below.
WORK_TIME
19:03:00
20:00:00
21:02:00
21:54:00
23:04:00
00:02:00
i want to create a database view using these data. for it i need to get Gap between these times as below.
WORK_TIME GAP
19:03:00 -
20:00:00 00:57:00 (Gap between 19:03:00 and 20:00:00)
21:02:00 01:02:00 (Gap between 20:00:00 and 21:02:00)
21:54:00 00:52:00 (Gap between 21:02:00 and 21:54:00)
23:04:00 01:10:00 (Gap between 21:54:00 and 23:04:00)
00:02:00 00:58:00 (Gap between 23:04:00 and 00:02:00)
How could i do this ?
This query will get you the differences in hours:
SELECT
work_time,
( work_time - LAG(work_time) OVER (ORDER BY work_time) ) * 24 AS gap
FROM emp_works
Example on SQL Fiddle returns this:
WORK_TIME GAP
November, 07 2012 19:03:00+0000 (null)
November, 07 2012 20:00:00+0000 0.95
November, 07 2012 21:02:00+0000 1.033333333333
November, 07 2012 21:54:00+0000 0.866666666667
November, 07 2012 23:04:00+0000 1.166666666667
November, 08 2012 00:02:00+0000 0.966666666667
First you will need to have a primary key in the table containing the DATE/TIME field.
I have set up this demo on SQL Fiddle .. Have a look
I have represented the gap as a factor of hours between the two times. You can manipulate the figure to represent minutes, or days, whatever.
SELECT
TO_CHAR(A.WORK_TIME,'HH24:MI:SS') WORK_FROM,
TO_CHAR(B.WORK_TIME,'HH24:MI:SS') WORK_TO,
ROUND(24*(B.WORK_TIME-A.WORK_TIME),2) GAP FROM
sample A,
SAMPLE B
WHERE A.ID+1 = B.ID(+)
If your primary key values have difference greater than 1 (gaps within the values of the primary key) then you will need to offset the value dynamically like this:
SELECT
TO_CHAR(A.WORK_TIME,'HH24:MI:SS') WORK_FROM,
TO_CHAR(B.WORK_TIME,'HH24:MI:SS') WORK_TO,
ROUND(24*(B.WORK_TIME-A.WORK_TIME),2) GAP FROM
sample A,
SAMPLE B
WHERE b.ID = (select min(C.ID) from sample c where c.id>A.ID)
According to your desired result, provided in the question, you want to see time interval. And also I suppose that the WORK_TIME column is of date datatype and there is a date part(otherwise there will be a negative result of subtraction (previous value of WORK_TIME from 00.02.00)).
SQL> create table Work_times(
2 work_time
3 ) as
4 (
5 select to_date('01.01.2012 19:03:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
6 select to_date('01.01.2012 20:00:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
7 select to_date('01.01.2012 21:02:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
8 select to_date('01.01.2012 21:54:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
9 select to_date('01.01.2012 23:04:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
10 select to_date('02.01.2012 00:02:00', 'dd.mm.yyyy hh24:mi:ss') from dual
11 )
12 /
Table created
SQL>
SQL> select to_char(t.work_time, 'hh24.mi.ss') work_time
2 , (t.work_time -
3 lag(t.work_time) over(order by WORK_TIME)) day(1) to second(0) Res
4 from work_times t
5 ;
WORK_TIME RES
--------- -------------------------------------------------------------------------------
19.03.00
20.00.00 +0 00:57:00
21.02.00 +0 01:02:00
21.54.00 +0 00:52:00
23.04.00 +0 01:10:00
00.02.00 +0 00:58:00
6 rows selected