I have a table with a date field and I need a query to return the ID of records that are on a certain day.
Example
ID UPDATED_DATE
42 31-DEC-19 12.00.00.000000000 AM
43 24-DEC-19 12.00.00.000000000 AM
44 03-DEC-19 12.00.00.000000000 AM
45 18-NOV-19 12.00.00.000000000 AM
46 08-NOV-19 12.00.00.000000000 AM
47 01-NOV-19 12.00.00.000000000 AM
48 26-OCT-19 12.00.00.000000000 AM
49 04-OCT-19 12.00.00.000000000 AM
50 20-SEP-19 12.00.00.000000000 AM
I need a query to find if the DAY part of the date is >= 1 and < 5.
In the example, I will get the ID as 44, 47 and 49 as output.
Can anyone help me for the query, please?
Use TO_CHAR with appropriate format mask:
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> with test as
2 (select 42 id, date '2019-12-31' updated_date from dual union all
3 select 43, date '2019-12-24' from dual union all
4 select 44, date '2019-12-03' from dual union all
5 select 45, date '2019-11-18' from dual union all
6 select 46, date '2019-11-08' from dual union all
7 select 47, date '2019-11-01' from dual union all
8 select 48, date '2019-10-26' from dual union all
9 select 49, date '2019-10-04' from dual union all
10 select 50, date '2019-09-20' from dual
11 )
12 select id, updated_date, to_char(updated_date, 'fmdd') dd
13 from test
14 where to_char(updated_date, 'fmdd') >= 1
15 and to_char(updated_date, 'fmdd') < 5
16 order by id;
ID UPDATED_DA DD
---------- ---------- --
44 03.12.2019 3
47 01.11.2019 1
49 04.10.2019 4
SQL>
If you want the difference (as per the original version of the question) between day-of-month of two rows to be between 1 and 4 days then use LAG/LEAD:
SELECT ID,
UPDATED_DATE
FROM (
SELECT ID,
UPDATED_DATE,
EXTRACT(DAY FROM updated_date) AS day,
LAG( EXTRACT(DAY FROM updated_date) )
OVER ( ORDER BY EXTRACT(DAY FROM updated_date) ) AS prev_day,
LEAD( EXTRACT(DAY FROM updated_date) )
OVER ( ORDER BY EXTRACT(DAY FROM updated_date) ) AS next_day
FROM table_name
)
WHERE day - prev_day BETWEEN 1 AND 4
OR next_day - day BETWEEN 1 AND 4
Which for your test data ouptuts:
ID | UPDATED_DATE
-: | :--------------------
47 | 01-NOV-19 12:00:00 AM
44 | 03-DEC-19 12:00:00 AM
49 | 04-OCT-19 12:00:00 AM
46 | 08-NOV-19 12:00:00 AM
45 | 18-NOV-19 12:00:00 AM
50 | 20-SEP-19 12:00:00 AM
43 | 24-DEC-19 12:00:00 AM
48 | 26-OCT-19 12:00:00 AM
If you want the day-of-month to be between 1 and 4 then use EXTRACT:
SELECT *
FROM table_name
WHERE EXTRACT(DAY FROM updated_date) BETWEEN 1 AND 4
Which outputs:
ID | UPDATED_DATE
-: | :--------------------
44 | 03-DEC-19 12:00:00 AM
47 | 01-NOV-19 12:00:00 AM
49 | 04-OCT-19 12:00:00 AM
db<>fiddle here
Related
I have one requirement where I have to show the records between specific date and time every day in one week duration.
in one week duration( 2019-04-01 till 2019-04-06) ,for instance record of 2019-04-01 at 19 PM till 8 Am of 2019-04-02 ,and record of 2019-04-02 at 19 PM till 08 AM of 2019-04-03 and ...
would you please help me!
Use recursive query to create proper periods then join with your data or do it simpler with condition like here:
select callbegin, callerno
from table4
where callerno in ('7032','750')
and callbegin between timestamp '2019-04-01 19:00:00'
and timestamp '2019-04-06 08:00:00'
and ('19' <= to_char(callbegin, 'hh24') or to_char(callbegin, 'hh24') < '08');
demo
Here's how I understood the question.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi';
Session altered.
SQL> break on period;
SQL> with
2 data (id, datum) as
3 (select 1, to_date('01.04.2019 15:30', 'dd.mm.yyyy hh24:mi') from dual union all
4 select 2, to_date('01.04.2019 20:00', 'dd.mm.yyyy hh24:mi') from dual union all -- 1st
5 select 3, to_date('02.04.2019 01:15', 'dd.mm.yyyy hh24:mi') from dual union all -- 1st perios
6 select 4, to_date('02.04.2019 11:00', 'dd.mm.yyyy hh24:mi') from dual union all
7 select 5, to_date('02.04.2019 23:15', 'dd.mm.yyyy hh24:mi') from dual union all -- 2nd period
8 select 6, to_date('03.04.2019 00:10', 'dd.mm.yyyy hh24:mi') from dual union all -- 2nd
9 select 7, to_date('04.04.2019 22:20', 'dd.mm.yyyy hh24:mi') from dual -- 3rd period
10 ),
11 test as
12 (select date '2019-04-01' dstart,
13 date '2019-04-06' dend
14 from dual
15 ),
16 inter as
17 (select dstart + level - 1 datum
18 from test
19 connect by level <= dend - dstart + 1
20 ),
21 from_to as
22 (select datum + 19/24 date_from,
23 lead(datum) over (order by datum) + 8/24 date_to
24 from inter
25 )
26 select f.date_From ||' - '|| f.date_to period,
27 d.id,
28 d.datum
29 from data d join from_to f on 1 = 1
30 where d.datum between f.date_from and f.date_to
31 order by f.date_From, d.id;
PERIOD ID DATUM
----------------------------------- ---------- ----------------
01.04.2019 19:00 - 02.04.2019 08:00 2 01.04.2019 20:00
3 02.04.2019 01:15
02.04.2019 19:00 - 03.04.2019 08:00 5 02.04.2019 23:15
6 03.04.2019 00:10
04.04.2019 19:00 - 05.04.2019 08:00 7 04.04.2019 22:20
SQL>
This is how to filter data by days and time by one week:
With date_list as (
Select
to_date(to_char( (sysdate - level), 'yyyymmdd') || '19', 'yyyymmddhh24') begin_time,
to_date(to_char( ((sysdate - level)+1), 'yyyymmdd') || '08', 'yyyymmddhh24') end_time
From dual connect by level <= 7
)
Select begin_time, your_table.*
From
your_table t1,
date_list t2
Where
t1.your_date between t2.begin_time and t2.end_time;
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
I need to postprocess a Oracle dataset in order to find the number of heat waves.
By definition, a heat waves occurs when the data value is greater than a threshold at least two consecutive times.
For example, given the threshold=20 and the sequence
23 31 32 17 16 23 16 21 22 18
the heat waves are 2:
{23,31,32} and {21,22}
and the lenght of the longest one is 3 (size of bigger subset)
My input dataset consists of several sequences; a sample input result set is:
-----------------------------
| ID | DAY | VALUE |
-----------------------------
| 100 | 1/1/17 | 20 |
| 100 | 2/1/17 | 21 |
| 200 | 1/1/17 | 12 |
| 200 | 2/1/17 | 24 |
| ... ... ...
In other words, I have a sequence per each ID and I need to output something like that:
-----------------------
| ID | #heat waves |
-----------------------
| 100 | 3 |
| 200 | 1 |
Here the current version of my stored procedure:
create or replace PROCEDURE sp (
p_query IN VARCHAR2,
cursor_ out sys_refcursor
) AS
processed processed_data_table := processed_data_table();
c sys_refcursor;
BEGIN
OPEN c FOR p_query;
processed.EXTEND;
processed(processed.count) := processed_data_obj();
fetch c INTO processed(processed.count).ID,
processed(processed.count).DAY, processed(processed.count).VALUE;
while c%found
processed.EXTEND;
processed(processed.count) := processed_data_obj();
fetch c INTO processed(processed.count).ID,
processed(processed.count).DAY, processed(processed.count).VALUE;
END loop;
CLOSE c;
processed.TRIM;
// HERE I NEED TO PROCESS processed TABLE AND STORE RESULT IN output
TABLE
OPEN cursor_ FOR
SELECT *
FROM TABLE( output);
END sp;
Anyone could help me providing a solution?
Thanks
In Oracle 12c, use MATCH_RECOGNIZE:
select id, count(*) "# of heatwaves" from series_data
match_recognize ( partition by id
order by day
one row per match
after match skip past last row
pattern ( over_threshold{2,} )
define
over_threshold as value > 20 )
group by id
UPDATE: Also show longest heat wave for each series
To get the longest heatwave in each series, we have to introduce a MEASURES clause to the MATCH_RECOGNIZE, as below:
select id,
max(heatwave_length) "longest heatwave",
count(distinct heatwave_number) "# of heatwaves"
from series_data
match_recognize ( partition by id
order by day
measures
FINAL COUNT(*) as heatwave_length,
MATCH_NUMBER() heatwave_number
all rows per match
after match skip past last row
pattern ( over_threshold{2,} )
define
over_threshold as value > 20 )
group by id
order by id;
Full example with data:
with series_data ( id, day, value ) as
( SELECT 100, date '2017-01-01', 23 from dual union all
SELECT 100, date '2017-01-02', 31 from dual union all
SELECT 100, date '2017-01-03', 32 from dual union all
SELECT 100, date '2017-01-04', 44 from dual union all
SELECT 100, date '2017-01-05', 16 from dual union all
SELECT 100, date '2017-01-06', 23 from dual union all
SELECT 100, date '2017-01-07', 16 from dual union all
SELECT 100, date '2017-01-08', 21 from dual union all
SELECT 100, date '2017-01-09', 22 from dual union all
SELECT 100, date '2017-01-10', 18 from dual union all
SELECT 200, date '2017-01-01', 23 from dual union all
SELECT 200, date '2017-01-02', 31 from dual union all
SELECT 200, date '2017-01-03', 32 from dual union all
SELECT 200, date '2017-01-04', 17 from dual union all
SELECT 200, date '2017-01-05', 16 from dual union all
SELECT 200, date '2017-01-06', 23 from dual union all
SELECT 200, date '2017-01-07', 16 from dual union all
SELECT 200, date '2017-01-08', 21 from dual union all
SELECT 200, date '2017-01-09', 22 from dual union all
SELECT 200, date '2017-01-10', 22 from dual union all
SELECT 200, date '2017-01-11', 6 from dual union all
SELECT 200, date '2017-01-12', 22 from dual union all
SELECT 200, date '2017-01-13', 22 from dual )
select id,
max(heatwave_length) "longest heatwave",
count(distinct heatwave_number) "# of heatwaves"
from series_data
match_recognize ( partition by id
order by day
measures
FINAL COUNT(*) as heatwave_length,
MATCH_NUMBER() heatwave_number
all rows per match
after match skip past last row
pattern ( over_threshold{2,} )
define
over_threshold as value > 20 )
group by id
order by id;
Results:
ID longest heatwave # of heatwaves
----- -------------- --------------
100 4 2
200 3 3
I have two tables, T_TEST and T_DEFAULT_DATE. T_TEST contains date and amount, and T_DEFAULT_DATE contains just P_DATE.
First table T_TEST:
DATE AMOUNT
-------- ----------
01.01.99 77
16.02.99 59
01.01.00 12
15.01.00 32
01.02.00 144
15.02.00 320
16.02.00 521
01.03.00 98
15.03.00 76
16.03.00 33
01.01.01 65
15.01.01 78
01.02.01 95
15.02.01 39
16.02.01 97
02.02.02 63
07.03.02 75
And second table T_DEFAULT_DATE:
P_DATE
--------
16.02.01
What I want to get is two queries established in a single query :
1. what is the amount of sale achieved on the same day last year (- 12 mounths)
2. amount of sales for whole past year (based on table T_DEFAULT_DATE)
3. the amount (sum) for whole mounth (default mounth : 1.2. 2001 - 28.2.2001)
Expected output is :
P_SDLY P_LY P_MS
-----------
521 1236 231
I tryed with add_months(t_default_date.p_date, -12) , but I didn't get expected result. Please help
You can try something like this, assuming that your fields are stored in date columns.
SQL> with t_test(date_, amount) as
2 (
3 select to_date('01.01.99', 'dd.mm.rr'), 77 from dual union all
4 select to_date('16.02.99', 'dd.mm.rr'), 59 from dual union all
5 select to_date('01.01.00', 'dd.mm.rr'), 12 from dual union all
6 select to_date('15.01.00', 'dd.mm.rr'), 32 from dual union all
7 select to_date('01.02.00', 'dd.mm.rr'), 144 from dual union all
8 select to_date('15.02.00', 'dd.mm.rr'), 320 from dual union all
9 select to_date('16.02.00', 'dd.mm.rr'), 521 from dual union all
10 select to_date('01.03.00', 'dd.mm.rr'), 98 from dual union all
11 select to_date('15.03.00', 'dd.mm.rr'), 76 from dual union all
12 select to_date('16.03.00', 'dd.mm.rr'), 33 from dual union all
13 select to_date('01.01.01', 'dd.mm.rr'), 65 from dual union all
14 select to_date('15.01.01', 'dd.mm.rr'), 78 from dual union all
15 select to_date('01.02.01', 'dd.mm.rr'), 95 from dual union all
16 select to_date('15.02.01', 'dd.mm.rr'), 39 from dual union all
17 select to_date('16.02.01', 'dd.mm.rr'), 97 from dual union all
18 select to_date('02.02.02', 'dd.mm.rr'), 63 from dual union all
19 select to_date('07.03.02', 'dd.mm.rr'), 75 from dual
20 ),
21 t_default_date(p_date) as
22 (
23 select to_date('16.02.01', 'dd.mm.rr') from dual
24 )
25 select sum(
26 case
27 when date_ between add_months(trunc(p_date, 'yyyy'), -12)
28 and trunc(p_date, 'yyyy')-1
29 then amount
30 else 0
31 end
32 ) as year,
33 sum( decode (date_, add_months(p_date, -12), amount, 0) ) as day,
34 sum( case
35 when date_ between
36 trunc(p_date, 'MM') and
37 last_day(p_date)
38 then amount
39 else
40 0
41 end
42 ) as month
43 from t_test
44 inner join t_default_date on (date_ between add_months(trunc(p_date, 'yyyy'), -12) and last_day(p_date) );
YEAR DAY MONTH
---------- ---------- ----------
1236 521 231
SQL>
This makes use of add_months to get exactly "one year ago"; if you need "365 days ago" (think of leap years), consider using something like date - 365
This question already has answers here:
Oracle SQL pivot query
(4 answers)
Closed 8 years ago.
this is my table in oracle 11g:
**date qty1 qty2 qty3 qty4**
2-Feb-14 61 64 52 54
2-Mar-14 124 130 149 156
i want to convert it into the following table. i.e. add 7 days to the date and transpose the qty. And i have till qty52 such metrics
***date qty***
**2-Feb-14 61**
9-Feb-14 64
16-Feb-14 52
23-Feb-14 54
**2-Mar-14 124**
9-Mar-14 130
16-Mar-14 149
23-Mar-14 156
have a try:
WITH t(my_date, val, val2, val3, val4)
AS (
SELECT to_date('01/01/2014 12:00:00 AM', 'dd/mm/yyyy hh:mi:ss am'), 1,2,3,4 from dual
UNION ALL
SELECT to_date('01/02/2014 12:00:00 AM', 'dd/mm/yyyy hh:mi:ss am'), 5,6,7,8 FROM dual
)
SELECT (my_date-7) + (row_number() OVER (partition by my_date ORDER BY my_date)*7) my_date, value as qty
FROM (
( SELECT my_date, val, val2, val3, val4 FROM t
) unpivot ( value FOR value_type IN (val, val2, val3, val4) ) );
output:
MY_DATE QTY
----------------------- ----------
01/01/2014 12:00:00 AM 1
08/01/2014 12:00:00 AM 2
15/01/2014 12:00:00 AM 3
22/01/2014 12:00:00 AM 4
01/02/2014 12:00:00 AM 5
08/02/2014 12:00:00 AM 6
15/02/2014 12:00:00 AM 7
22/02/2014 12:00:00 AM 8
select date,qty from
(select date,qty1 as qty
from tbl
union
select date+7 as date,qty2 as qty
from tbl
union
select date+14 as date,qty3 as qty
from tbl
union
select date+21 as date,qty4 as qty
from tbl)
order by date
If you've got Oracle 11g, I'd look at doing it with UNPIVOT.
select
start_date + to_number(week_number) * 7,
qty
from (
select *
from quantity_data
unpivot (qty for week_number
in (qty1 as '0', qty2 as '1', qty3 as '2', qty4 as '3'))
)
This is an alternative to the example from ajmalmhd04, using to_number instead of the row_number analytic function. The answer from ajmalmhd04 is probably more generic though
If you haven't got Oracle 11g then try this for an option:
with pivot_data as (
select 0 as pivot_col from dual union all
select 1 from dual union all
select 2 from dual union all
select 3 from dual
)
select
start_date + (7 * pivot_col) as start_date,
case
when pivot_col = 0 then qty1
when pivot_col = 1 then qty2
when pivot_col = 2 then qty3
when pivot_col = 3 then qty4 end as qty
from
quantity_data cross join pivot_data
order by 1
Try this
with tab(date_d,qty1,qty2,qty3,qty4) as (
select '2-Feb-14',61,64,52,54 from dual union all
select '2-Mar-14',124,130,149,156 from dual),
tab2(dd, ss) as (select date_d, qty1||','||qty2||','||qty3||','||qty4 from tab)
select to_date(dd) + ((level-1) * 7) "DATE", regexp_substr(ss, '[^(,)]+', 1, level) "QTY"
from tab2
connect by level <= length(ss) - length(replace(ss, ',')) + 1
and prior ss = ss
and prior sys_guid() is not null
output
| DATE | QTY |
|---------------------------------|-----|
| March, 02 2014 00:00:00+0000 | 124 |
| March, 09 2014 00:00:00+0000 | 130 |
| March, 16 2014 00:00:00+0000 | 149 |
| March, 23 2014 00:00:00+0000 | 156 |
| February, 02 2014 00:00:00+0000 | 61 |
| February, 09 2014 00:00:00+0000 | 64 |
| February, 16 2014 00:00:00+0000 | 52 |
| February, 23 2014 00:00:00+0000 | 54 |
Let me know if it meets your requirement.