I have a table which i want to only output 1 field from so it can be part of another queries WHERE statement (WHERE SID IN (THIS NEW QUERY)).
However because of this i can only include SID in the SELECT, but this is removing that is needed to make the distinct count work.
SO SELECT * FROM Tablea gives me:
SID deta detb
22222 8159 3763
22222 8159 3763
44444 4739 6135
44444 4739 6135
44444 4739 6134
44444 4739 6135
55555 5937 0223
55555 5936 0223
66666 8577 9497
66666 8577 9497
66666 8577 9497
66666 8576 9496
66666 8577 9497
88888 3595 0919
88888 3595 0919
88888 3595 0919
88888 3595 0914
77777 5678 3456
Then SELECT DISTINCT SID, deta, detb FROM Tablea gives me:
SID deta detb
22222 8159 3763
44444 4739 6134
44444 4739 6135
55555 5936 0223
55555 5937 0223
66666 8576 9496
66666 8577 9497
88888 3595 0914
88888 3595 0919
77777 5678 3456
The data i want is this:
SID deta detb
44444 4739 6134
44444 4739 6135
55555 5936 0223
55555 5937 0223
66666 8576 9496
66666 8577 9497
88888 3595 0914
88888 3595 0919
Which can be done by using a count of distinct, however my final output i want is this:
SID
44444
55555
66666
88888
But i cant achieve it when only outputting 1 field.
Use group by:
SELECT SID
FROM Tablea
GROUP BY SID
HAVING COUNT(DISTINCT deta || ':' || detab) > 1;
If you actually wanted the full rows (instead of the SID values), then use window functions:
SELECT a.*
FROM (SELECT a.*, COUNT(DISTINCT deta || ':' || detab) OVER (PARTITION BY SID) as cnt
FROM tablea a
) a
WHERE cnt > 1;
I would do it like this:
with sample_data (SID, deta, detb) as (select 22222, 8159, 3763 from dual union all
select 22222, 8159, 3763 from dual union all
select 44444, 4739, 6135 from dual union all
select 44444, 4739, 6135 from dual union all
select 44444, 4739, 6134 from dual union all
select 44444, 4739, 6135 from dual union all
select 55555, 5937, 0223 from dual union all
select 55555, 5936, 0223 from dual union all
select 66666, 8577, 9497 from dual union all
select 66666, 8577, 9497 from dual union all
select 66666, 8577, 9497 from dual union all
select 66666, 8576, 9496 from dual union all
select 66666, 8577, 9497 from dual union all
select 88888, 3595, 0919 from dual union all
select 88888, 3595, 0919 from dual union all
select 88888, 3595, 0919 from dual union all
select 88888, 3595, 0914 from dual union all
select 77777, 5678, 3456 from dual)
--- end of mimicking your sample data
select sid
from (select distinct sid,
deta,
detb
from sample_data)
group by sid
having count(*) > 1;
SID
----------
44444
66666
55555
88888
Related
I need to get 3 data
The sum of data between n dates / days
like, I need to get the sum of 01-12 to 05-12 and this / days = 5
The result of 1 but this is for validation
The difference between #1 and #2
How to get the sum of data from different dates also I need this 3 points for every segment I have like
segment
1
2
3
TTT
456465
456465
0
CCC
478888
478886
2
select segment,
(SELECT var1 AS 1.-
+ ( SELECT var1 AS 1.-
from table
where data = 20221207
group by segement
)
from table
where data = 20221206
group by segement) AS 1.-,
sum(IMP_SDO_MED_CONT_ML) AS 2.-,
(1.- - 2.-) AS difference,
from table
WHERE DATA = 20221207
group by segment;
You appear to want to sum the data using conditional aggregation and then can find #3 using subtraction:
SELECT segment,
SUM(CASE WHEN data BETWEEN 20221201 AND 20221212 THEN var1 END) AS "1",
SUM(IMP_SDO_MED_CONT_ML) AS "2",
SUM(CASE WHEN data BETWEEN 20221201 AND 20221212 THEN var1 END)
- SUM(IMP_SDO_MED_CONT_ML) AS "3"
FROM table_name
GROUP BY segment
However, without sample input data it is difficult to check what you are expecting.
It's realy hard to tell what the question is without the data. Maybe it is about calculating the difference of sums of two columns in some period per segments. If that is the case then the query would be:
Select
SEGMENT,
Sum(var_1) "FLD_1",
Sum(IMP_SDO_MED_CONT_ML) "FLD_2",
Sum(var_1) - Sum(IMP_SDO_MED_CONT_ML) "DIFF"
From a_tbl
Where DATE_NUMBER Between 20221201 And 20221203
Group By SEGMENT
Order By SEGMENT
... and if we invent some sample data like below
WITH
a_tbl AS
(
Select 'AAA' "SEGMENT", 1234 "VAR_1", 1233 "IMP_SDO_MED_CONT_ML", 20221201 "DATE_NUMBER" From Dual Union All
Select 'AAA' "SEGMENT", 5678 "VAR_1", 5677 "IMP_SDO_MED_CONT_ML", 20221202 "DATE_NUMBER" From Dual Union All
Select 'AAA' "SEGMENT", 9101 "VAR_1", 9103 "IMP_SDO_MED_CONT_ML", 20221203 "DATE_NUMBER" From Dual Union All
Select 'BBB' "SEGMENT", 8765 "VAR_1", 8766 "IMP_SDO_MED_CONT_ML", 20221201 "DATE_NUMBER" From Dual Union All
Select 'BBB' "SEGMENT", 6666 "VAR_1", 6665 "IMP_SDO_MED_CONT_ML", 20221202 "DATE_NUMBER" From Dual Union All
Select 'BBB' "SEGMENT", 4423 "VAR_1", 4420 "IMP_SDO_MED_CONT_ML", 20221203 "DATE_NUMBER" From Dual Union All
Select 'CCC' "SEGMENT", 1234 "VAR_1", 1233 "IMP_SDO_MED_CONT_ML", 20221201 "DATE_NUMBER" From Dual Union All
Select 'CCC' "SEGMENT", 5678 "VAR_1", 5677 "IMP_SDO_MED_CONT_ML", 20221203 "DATE_NUMBER" From Dual Union All
Select 'DDD' "SEGMENT", 1234 "VAR_1", 1233 "IMP_SDO_MED_CONT_ML", 20221201 "DATE_NUMBER" From Dual Union All
Select 'EEE' "SEGMENT", 5678 "VAR_1", 5678 "IMP_SDO_MED_CONT_ML", 20221203 "DATE_NUMBER" From Dual
)
... then the result would be
SEGMENT
FLD_1
FLD_2
DIFF
AAA
16013
16013
0
BBB
19854
19851
3
CCC
6912
6910
2
DDD
1234
1233
1
EEE
5678
5678
0
OR maybe it is the difference between sum of the period for one column and sum of the last day of period for the other column. In that case query could be:
Select
SEGMENT,
Sum(var_1) "FLD_1",
Sum(CASE WHEN DATE_NUMBER = 20221203 THEN IMP_SDO_MED_CONT_ML ELSE 0 END) "FLD_2",
Sum(var_1) - Sum(CASE WHEN DATE_NUMBER = 20221203 THEN IMP_SDO_MED_CONT_ML ELSE 0 END) "DIFF"
From a_tbl
Where DATE_NUMBER Between 20221201 And 20221203
Group By SEGMENT
Order By SEGMENT
... resulting (with same invented data) as
SEGMENT
FLD_1
FLD_2
DIFF
AAA
16013
9103
6910
BBB
19854
4420
15434
CCC
6912
5677
1235
DDD
1234
0
1234
EEE
5678
5678
0
How would I modify the following SQL query code to return the latest entry of each employee per hour, instead of currently returning every occurrence from each employee regardless of how many times it appears in the query per each hour.
I've attached example data for the order of what currently would be in the database and the desired table output. Note: you can see it's in descending order and 2 entries (0001 and 0009) are omitted because they came from the same employees within an hour interval.
SQL Query Code:
select
TRANSACTION_ID
EMPLOYEE_ID
FIRST_NAME
LAST_NAME
TIME_STAMP
from (select d.*,
row_number() over (partition by EMPLOYEE_ID, trunc(TIME_STAMP, 'HH') order by TIME_STAMP desc) as SEQNUM
from MAIN.DATABASE d
) d
where SEQNUM = 1;
order by TRANSACTION_ID desc;
This is the current order of the data in the database:
TRANSACTION_ID
EMPLOYEE_ID
FIRST_NAME
LAST_NAME
TIME_STAMP
0001
AAAA
Adam
Akbar
10/05/2021 04:42:42.000 PM
0004
BBBB
Barry
Brink
10/06/2021 07:25:25.000 AM
0003
CCCC
Charlie
Che
10/06/2021 07:15:15.000 AM
0005
DDDD
David
Doe
10/06/2021 07:27:27.000 AM
0006
EEEE
Eric
Erickson
10/06/2021 07:29:29.000 AM
0007
FFFF
Fred
Foe
10/06/2021 07:31:31.000 AM
0008
GGGG
George
Guy
10/06/2021 07:33:33.000 AM
0010
HHHH
Henry
Hugh
10/06/2021 07:55:55.000 AM
0009
HHHH
Henry
Hugh
10/06/2021 07:54:54.000 AM
0002
AAAA
Adam
Akbar
10/05/2021 04:43:43.000 PM
This is what should be returned:
TRANSACTION_ID
EMPLOYEE_ID
FIRST_NAME
LAST_NAME
TIME_STAMP
0010
HHHH
Henry
Hugh
10/06/2021 07:55:55.000 AM
0008
GGGG
George
Guy
10/06/2021 07:33:33.000 AM
0007
FFFF
Fred
Foe
10/06/2021 07:31:31.000 AM
0006
EEEE
Eric
Erickson
10/06/2021 07:29:29.000 AM
0005
DDDD
David
Doe
10/06/2021 07:27:27.000 AM
0004
BBBB
Barry
Brink
10/06/2021 07:25:25.000 AM
0003
CCCC
Charlie
Che
10/06/2021 07:15:15.000 AM
0002
AAAA
Adam
Akbar
10/05/2021 04:43:43.000 PM
However, this is what the code is currently returning as written:
TRANSACTION_ID
EMPLOYEE_ID
FIRST_NAME
LAST_NAME
TIME_STAMP
0010
HHHH
Henry
Hugh
10/06/2021 07:55:55.000 AM
0006
EEEE
Eric
Erickson
10/06/2021 07:29:29.000 AM
0003
CCCC
Charlie
Che
10/06/2021 07:15:15.000 AM
0002
AAAA
Adam
Akbar
10/05/2021 04:43:43.000 PM
Any idea what I'm missing and how I can fix it?
The query ( in order to return what you want ) should work as this. However., I am assuming your field time_stamp is really a timestamp in the format you provided.
SQL> set lines 220
SQL> with x ( transaction_id , employee_id, first_name, last_name, time_stamp )
2 as
3 (
4 select '0001' , 'AAAA', 'Adam' , 'Akbar' , to_timestamp('10/05/2021 04:42:42.000 PM','MM/DD/YYYY HH:MI:SS.FF3 PM') from dual union all
5 select '0004' , 'BBBB', 'Barry' , 'Brink' , to_timestamp('10/06/2021 07:25:25.000 AM','MM/DD/YYYY HH:MI:SS.FF3 AM') from dual union all
6 select '0003' , 'CCCC', 'Charlie' , 'Che' , to_timestamp('10/06/2021 07:15:15.000 AM','MM/DD/YYYY HH:MI:SS.FF3 AM') from dual union all
7 select '0005' , 'DDDD', 'David' , 'Doe' , to_timestamp('10/06/2021 07:27:27.000 AM','MM/DD/YYYY HH:MI:SS.FF3 AM') from dual union all
8 select '0006' , 'EEEE', 'Eric' , 'Erickson' , to_timestamp('10/06/2021 07:29:29.000 AM','MM/DD/YYYY HH:MI:SS.FF3 AM') from dual union all
9 select '0007' , 'FFFF', 'Fred' , 'Foe' , to_timestamp('10/06/2021 07:31:31.000 AM','MM/DD/YYYY HH:MI:SS.FF3 AM') from dual union all
10 select '0008' , 'GGGG', 'George' , 'Guy' , to_timestamp('10/06/2021 07:33:33.000 AM','MM/DD/YYYY HH:MI:SS.FF3 AM') from dual union all
11 select '0010' , 'HHHH', 'Henry' , 'Hugh' , to_timestamp('10/06/2021 07:55:55.000 AM','MM/DD/YYYY HH:MI:SS.FF3 AM') from dual union all
12 select '0009' , 'HHHH', 'Henry' , 'Hugh' , to_timestamp('10/06/2021 07:54:54.000 AM','MM/DD/YYYY HH:MI:SS.FF3 AM') from dual union all
13 select '0002' , 'AAAA', 'Adam' , 'Akbar' , to_timestamp('10/05/2021 04:43:43.000 PM','MM/DD/YYYY HH:MI:SS.FF3 PM') from dual
14 )
15 select
16 TRANSACTION_ID ,
17 EMPLOYEE_ID ,
18 FIRST_NAME ,
19 LAST_NAME ,
20 TIME_STAMP
21 from (select x.*,
22 row_number() over (partition by EMPLOYEE_ID, trunc(TIME_STAMP, 'HH') order by TIME_STAMP desc) as SEQNUM
23 from x
24 )
25 where SEQNUM = 1
26* order by TRANSACTION_ID desc
TRAN EMPL FIRST_N LAST_NAM TIME_STAMP
---- ---- ------- -------- ---------------------------------------------------------------------------
0010 HHHH Henry Hugh 06-OCT-21 07.55.55.000000000 AM
0008 GGGG George Guy 06-OCT-21 07.33.33.000000000 AM
0007 FFFF Fred Foe 06-OCT-21 07.31.31.000000000 AM
0006 EEEE Eric Erickson 06-OCT-21 07.29.29.000000000 AM
0005 DDDD David Doe 06-OCT-21 07.27.27.000000000 AM
0004 BBBB Barry Brink 06-OCT-21 07.25.25.000000000 AM
0003 CCCC Charlie Che 06-OCT-21 07.15.15.000000000 AM
0002 AAAA Adam Akbar 05-OCT-21 04.43.43.000000000 PM
8 rows selected.
SQL>
Your query is:
missing commas between the terms in the SELECT clause; and
has a ; after the WHERE filter and before the ORDER BY clause.
If you fix those issues then you get the code:
select TRANSACTION_ID,
EMPLOYEE_ID,
FIRST_NAME,
LAST_NAME,
TIME_STAMP
from (
select d.*,
row_number() over (
partition by EMPLOYEE_ID, trunc(TIME_STAMP, 'HH')
order by TIME_STAMP desc
) as SEQNUM
from MAIN.DATABASE d
) d
where SEQNUM = 1
order by TRANSACTION_ID desc;
Which, for the sample data:
CREATE TABLE main.database (TRANSACTION_ID, EMPLOYEE_ID, FIRST_NAME, LAST_NAME, TIME_STAMP ) AS
SELECT '0001', 'AAAA', 'Adam', 'Akbar', TIMESTAMP '2021-05-10 16:42:42.000' FROM DUAL UNION ALL
SELECT '0004', 'BBBB', 'Barry', 'Brink', TIMESTAMP '2021-06-10 07:25:25.000' FROM DUAL UNION ALL
SELECT '0003', 'CCCC', 'Charlie', 'Che', TIMESTAMP '2021-06-10 07:15:15.000' FROM DUAL UNION ALL
SELECT '0005', 'DDDD', 'David', 'Doe', TIMESTAMP '2021-06-10 07:27:27.000' FROM DUAL UNION ALL
SELECT '0006', 'EEEE', 'Eric', 'Erickson', TIMESTAMP '2021-06-10 07:29:29.000' FROM DUAL UNION ALL
SELECT '0007', 'FFFF', 'Fred', 'Foe', TIMESTAMP '2021-06-10 07:31:31.000' FROM DUAL UNION ALL
SELECT '0008', 'GGGG', 'George', 'Guy', TIMESTAMP '2021-06-10 07:33:33.000' FROM DUAL UNION ALL
SELECT '0010', 'HHHH', 'Henry', 'Hugh', TIMESTAMP '2021-06-10 07:55:55.000' FROM DUAL UNION ALL
SELECT '0009', 'HHHH', 'Henry', 'Hugh', TIMESTAMP '2021-06-10 07:54:54.000' FROM DUAL UNION ALL
SELECT '0002', 'AAAA', 'Adam', 'Akbar', TIMESTAMP '2021-05-10 16:43:43.000' FROM DUAL;
Works as expected:
TRANSACTION_ID
EMPLOYEE_ID
FIRST_NAME
LAST_NAME
TIME_STAMP
0010
HHHH
Henry
Hugh
10-JUN-21 07.55.55.000000000
0008
GGGG
George
Guy
10-JUN-21 07.33.33.000000000
0007
FFFF
Fred
Foe
10-JUN-21 07.31.31.000000000
0006
EEEE
Eric
Erickson
10-JUN-21 07.29.29.000000000
0005
DDDD
David
Doe
10-JUN-21 07.27.27.000000000
0004
BBBB
Barry
Brink
10-JUN-21 07.25.25.000000000
0003
CCCC
Charlie
Che
10-JUN-21 07.15.15.000000000
0002
AAAA
Adam
Akbar
10-MAY-21 16.43.43.000000000
db<>fiddle here
I have the below tables. The join from cycle to program is date based.
There are millions of PGMID entries, so I was thinking about pivoting feature but I can't hard code the PGMID. Any thoughts/help would be appreciated.
I do have the ability to edit tables in the db.
Table: Cycle
ID START_CYCLE END_CYCLE
4400 7/22/2018 8/3/2018
4400 8/4/2018 8/5/2018
4400 8/6/2018 8/6/2018
4400 8/7/2018 8/9/2018
4400 8/10/2018 9/6/2018
4400 9/7/2018 9/7/2018
4400 9/8/2018 9/9/2018
4400 9/10/2018 12/31/9999
Table: Program
PGMID START_DT END_DT
101 8/4/2018 9/10/2018
102 9/8/2018 9/8/2018
103 9/10/2018 NULL
Output:
ID START_CYCLE END_CYCLE PGMID
4400 7/22/2018 8/3/2018
4400 8/4/2018 8/5/2018 101
4400 8/6/2018 8/6/2018 101
4400 8/7/2018 8/9/2018 101
4400 8/10/2018 9/6/2018 101
4400 9/7/2018 9/7/2018 101
4400 9/8/2018 9/9/2018 101
4400 9/8/2018 9/9/2018 102
4400 9/10/2018 12/31/9999 103
There are duplicate cycle entries, I do NOT want any repeat dates.
4400 9/8/2018 9/9/2018 101
4400 9/8/2018 9/9/2018 102
Expected output:
ID START_CYCLE END_CYCLE PROGRAM1 PROGRAM2
4400 7/22/2018 8/3/2018
4400 8/4/2018 8/5/2018 101
4400 8/6/2018 8/6/2018 101
4400 8/7/2018 8/9/2018 101
4400 8/10/2018 9/6/2018 101
4400 9/7/2018 9/7/2018 101
4400 9/8/2018 9/9/2018 101 102
4400 9/10/2018 12/31/9999 103
select *
from (
select id, start_cycle, end_cycle, pgmid, case when rn > 5 then 0 else rn end rn
from (
select id, start_cycle, end_cycle, pgmid,
row_number() over (partition by id, start_cycle, end_cycle order by pgmid) rn
from cycle c
left join program p on p.start_dt <= c.end_cycle and c.start_cycle <= p.end_dt ))
pivot (listagg(pgmid, ',') within group (order by pgmid)
for rn in (1 program1, 2 program2, 3 program3, 4 program4, 5 program5, 0 others))
order by id, start_cycle
left join data as you did,
add row_number() partitioned by each cycle and ordered by pgmid,
if this number exceeds some number (in my case it is 5) then assign 0 instead,
make pivot using this column. First five columns are built as always, last which may contain more program is called others
instead of typically used in pivot min or max use listagg
These steps were needed to show all programs if there are more than 5 of them per cycle. All the rest are in others. If you know that there can be no more than, let's say 3 programs, then you can simplify this query.
If you want each program in different column and number of maximum columns is unknown then it's dynamic pivot problem. There are some solutions already described on Stack Overflow, but these are mostly workarounds.
Here is an example where we have up to 8 programs in one cycle:
with
cycle(id, start_cycle, end_cycle) as (
select 4400, date '2018-07-22', date '2018-08-03' from dual union all
select 4400, date '2018-08-04', date '2018-08-05' from dual union all
select 4400, date '2018-08-06', date '2018-08-06' from dual union all
select 4400, date '2018-08-07', date '2018-08-09' from dual union all
select 4400, date '2018-08-10', date '2018-09-06' from dual union all
select 4400, date '2018-09-07', date '2018-09-07' from dual union all
select 4400, date '2018-09-08', date '2018-09-09' from dual union all
select 4400, date '2018-09-10', date '9999-12-31' from dual ),
program(pgmid, start_dt, end_dt) as (
select 101, date '2018-08-04', date '2018-09-10' from dual union all
select 104, date '2018-08-06', date '2018-08-07' from dual union all
select 105, date '2018-08-06', date '2018-08-07' from dual union all
select 106, date '2018-08-06', date '2018-08-07' from dual union all
select 107, date '2018-08-06', date '2018-08-07' from dual union all
select 108, date '2018-08-06', date '2018-08-07' from dual union all
select 109, date '2018-08-06', date '2018-08-07' from dual union all
select 110, date '2018-08-07', date '2018-08-07' from dual union all
select 102, date '2018-09-08', date '2018-09-08' from dual union all
select 103, date '2018-09-10', null from dual )
select *
from (
select id, start_cycle, end_cycle, pgmid, case when rn > 5 then 0 else rn end rn
from (
select id, start_cycle, end_cycle, pgmid,
row_number() over (partition by id, start_cycle, end_cycle order by pgmid) rn
from cycle c
left join program p on p.start_dt <= c.end_cycle and c.start_cycle <= p.end_dt ))
pivot (listagg(pgmid, ',') within group (order by pgmid)
for rn in (1 program1, 2 program2, 3 program3, 4 program4, 5 program5, 0 others))
order by id, start_cycle
Result:
ID START_CYCLE END_CYCLE PROGRAM1 PROGRAM2 PROGRAM3 PROGRAM4 PROGRAM5 OTHERS
----- ----------- ----------- --------- --------- --------- --------- --------- ------------
4400 2018-07-22 2018-08-03
4400 2018-08-04 2018-08-05 101
4400 2018-08-06 2018-08-06 101 104 105 106 107 108,109
4400 2018-08-07 2018-08-09 101 104 105 106 107 108,109,110
4400 2018-08-10 2018-09-06 101
4400 2018-09-07 2018-09-07 101
4400 2018-09-08 2018-09-09 101 102
4400 2018-09-10 9999-12-31 101
dbfiddle demo
1- You must be add "group by START_CYCLE, END_CYCLE"
2- In select section must be add group_concat(PGMID separator ',')
I don't knowledge of oracle for above but in mysql is :
select ..., group_concat(PGMID separator ',') as PGMIDs, ...
from ...
join ...
where ...
group by START_CYCLE, END_CYCLE
I hope to help you.
I have data in my oracle table where I have names and date rages as following:
Name From To
Lopes, Janine 07-Jun-17 16-Jul-17
Lopes, Janine 17-Jul-17 23-Jul-17
Lopes, Janine 24-Jul-17 31-Aug-17
Baptista, Maria 23-Dec-16 19-Feb-17
Deyak,Sr, Thomas 22-Jan-17 18-Apr-17
Deyak,Sr, Thomas 27-Apr-17 14-May-17
Deyak,Sr, Thomas 15-May-17 21-May-17
Deyak,Sr, Thomas 22-May-17 28-May-17
Deyak,Sr, Thomas 29-May-17 31-May-17
Serrentino, Joyce 18-Mar-17 30-Apr-17
More, Cathleen 30-Jul-17 13-Aug-17
More, Cathleen 14-Aug-17 20-Aug-17
More, Cathleen 21-Aug-17 27-Aug-17
More, Cathleen 28-Aug-17 03-Sep-17
More, Cathleen 04-Sep-17 10-Sep-17
More, Cathleen 11-Sep-17 24-Sep-17
Barrows, Michael 30-Jan-17 19-Mar-17
Barrows, Michael 20-Mar-17 26-Mar-17
Barrows, Michael 27-Mar-17 02-Apr-17
Barrows, Michael 03-Apr-17 07-Apr-17
Mostly for one user the to date is one greater than from date and is continuous but in some cases there is break the data so my output should look like this:
Name From To
Lopes, Janine 07-Jun-17 31-Aug-17
Baptista, Maria 23-Dec-16 19-Feb-17
Deyak,Sr, Thomas 22-Jan-17 18-Apr-17
Deyak,Sr, Thomas 27-Apr-17 31-May-17
Serrentino, Joyce 18-Mar-17 30-Apr-17
More, Cathleen 30-Jul-17 24-Sep-17
Barrows, Michael 30-Jan-17 07-Apr-17
If I do min(from) and max(to) I loose some records like for Thomas.
How should I write sql to get the data is I require.
In Oracle 12.1 and above, the MATCH_RECOGNIZE clause does quick work of such requirements. I am using the same setup and simulated data (WITH clause) from my other answer, and the output is also the same.
select name, date_fr, date_to
from inputs
match_recognize(
partition by name
order by date_fr
measures a.date_fr as date_fr,
last(date_to) as date_to
pattern ( a b* )
define b as date_fr = prev(date_to) + 1
)
;
This can be solved nicely with the Tabibitosan method.
Preparation:
alter session set nls_date_format = 'dd-Mon-rr';
Session altered.
;
Query (including simulated inputs for convenience):
with
inputs ( name, date_fr, date_to ) as (
select 'Lopes, Janine' , to_date('07-Jun-17'), to_date('16-Jul-17') from dual union all
select 'Lopes, Janine' , to_date('17-Jul-17'), to_date('23-Jul-17') from dual union all
select 'Lopes, Janine' , to_date('24-Jul-17'), to_date('31-Aug-17') from dual union all
select 'Baptista, Maria' , to_date('23-Dec-16'), to_date('19-Feb-17') from dual union all
select 'Deyak,Sr, Thomas' , to_date('22-Jan-17'), to_date('18-Apr-17') from dual union all
select 'Deyak,Sr, Thomas' , to_date('27-Apr-17'), to_date('14-May-17') from dual union all
select 'Deyak,Sr, Thomas' , to_date('15-May-17'), to_date('21-May-17') from dual union all
select 'Deyak,Sr, Thomas' , to_date('22-May-17'), to_date('28-May-17') from dual union all
select 'Deyak,Sr, Thomas' , to_date('29-May-17'), to_date('31-May-17') from dual union all
select 'Serrentino, Joyce', to_date('18-Mar-17'), to_date('30-Apr-17') from dual union all
select 'More, Cathleen' , to_date('30-Jul-17'), to_date('13-Aug-17') from dual union all
select 'More, Cathleen' , to_date('14-Aug-17'), to_date('20-Aug-17') from dual union all
select 'More, Cathleen' , to_date('21-Aug-17'), to_date('27-Aug-17') from dual union all
select 'More, Cathleen' , to_date('28-Aug-17'), to_date('03-Sep-17') from dual union all
select 'More, Cathleen' , to_date('04-Sep-17'), to_date('10-Sep-17') from dual union all
select 'More, Cathleen' , to_date('11-Sep-17'), to_date('24-Sep-17') from dual union all
select 'Barrows, Michael' , to_date('30-Jan-17'), to_date('19-Mar-17') from dual union all
select 'Barrows, Michael' , to_date('20-Mar-17'), to_date('26-Mar-17') from dual union all
select 'Barrows, Michael' , to_date('27-Mar-17'), to_date('02-Apr-17') from dual union all
select 'Barrows, Michael' , to_date('03-Apr-17'), to_date('07-Apr-17') from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your actual table and column names.
select name, min(date_fr) as date_fr, max(date_to) as date_to
from ( select name, date_fr, date_to,
date_to - sum( date_to - date_fr + 1 ) over (partition by name
order by date_fr) as gr
from inputs
)
group by name, gr
order by name, date_fr
;
Output:
NAME DATE_FR DATE_TO
----------------- --------- ---------
Baptista, Maria 23-Dec-16 19-Feb-17
Barrows, Michael 30-Jan-17 07-Apr-17
Deyak,Sr, Thomas 22-Jan-17 18-Apr-17
Deyak,Sr, Thomas 27-Apr-17 31-May-17
Lopes, Janine 07-Jun-17 31-Aug-17
More, Cathleen 30-Jul-17 24-Sep-17
Serrentino, Joyce 18-Mar-17 30-Apr-17
7 rows selected
I'm using oracle and below are the details
SQL> with t as (select 12345 as ID,1 as TASK_ID,-1 as ASSIGNED_ID,null as ASSIGNED_GRP,sysdate-12/24 as ASSIGNED_DATE from dual union all
select 12345,2,67890,null,sysdate-11/24 from dual union all
select 12345,2,78901,null,sysdate-10/24 from dual union all
select 12345,2,-1,1111,sysdate-09/24 from dual union all
select 12345,2,67890,null,sysdate-08/24 from dual union all
select 12345,2,-1,2222,sysdate-07/24 from dual union all
select 12345,2,78901,null,sysdate-06/24 from dual union all
select 12346,2,67890,null,sysdate-05/24 from dual union all
select 12346,2,-1,1111,sysdate-04/24 from dual union all
select 12346,2,67890,null,sysdate-03/24 from dual union all
select 12346,2,78901,null,sysdate-02/24 from dual)
select ID,decode(ASSIGNED_GRP, NULL, decode(ASSIGNED_ID, NULL, '*', '-1', '*', ASSIGNED_ID), ASSIGNED_GRP),ASSIGNED_DATE from t;
ID DECODE(ASSIGNED_GRP,NULL,DECODE(ASSIGNED ASSIGNED_DATE
-------- ---------------------------------------- -----------------
12345 * 25-APR-2014 11:33
12345 67890 25-APR-2014 12:33
12345 78901 25-APR-2014 13:33
12345 1111 25-APR-2014 14:33
12345 67890 25-APR-2014 15:33
12345 2222 25-APR-2014 16:33
12345 78901 25-APR-2014 17:33
12346 67890 25-APR-2014 18:33
12346 1111 25-APR-2014 19:33
12346 67890 25-APR-2014 20:33
12346 78901 25-APR-2014 21:33
I'm looking for Expected output as below
ID ASSIGNED Hours
-----------------
12345 67890 2
12345 78901 2
12345 1111 1
12345 2222 1
12346 67890 2
12346 78901 2
12345 1111 1
I have tried doing this using the time lag parameter but facing problem having the decode function. Could you please advise
You seem to be counting the rows that match the conditions.
The following generates the result set you want, albeit in a different order:
select ID,
decode(ASSIGNED_GRP, NULL, decode(ASSIGNED_ID, NULL, '*', '-1', '*', ASSIGNED_ID), ASSIGNED_GRP),
count(*)
from t
where assigned_grp is not null or (assigned_id is not null and assigned_id <> -1)
group by ID,
decode(ASSIGNED_GRP, NULL, decode(ASSIGNED_ID, NULL, '*', '-1', '*', ASSIGNED_ID), ASSIGNED_GRP)
order by 1, 2 ;
sqlfiddle.com