Oracle decode+date+single row - sql

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

Related

Pivot: Create column to capture duplicate cycle dates

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.

Need help on Hive query

hive> describe hivecustomers;
OK
cust_id int
cust_fname string
cust_lname string
cust_email string
cust_password string
cust_street string
cust_city string
cust_state string
cust_zipcode string
hive> describe hiveorders;
OK
ord_id int
ord_dt string
ord_cust_id int
ord_stat string
hive> select * from hiveorders limit 3;
OK
1 2013-07-25 00:00:00.0 11599 CLOSED
2 2013-07-25 00:00:00.0 256 PENDING_PAYMENT
3 2013-07-25 00:00:00.0 12111 COMPLETE
hive> select * from hivecustomers limit 3;
OK
1 Richard Hernandez XXXXXXXXX XXXXXXXXX 6303 Heather Plaza Brownsville TX 78521
2 Mary Barrett XXXXXXXXX XXXXXXXXX 9526 Noble Embers Ridge Littleton CO 80126
3 Ann Smith XXXXXXXXX XXXXXXXXX 3422 Blue Pioneer Bend Caguas PR 00725
Based on the above two tables, I need output as following in Hive, how can I write query to this job ?
+-----------+---------------+---------------+--------------+-----+
|Cust Name | Cust Address | Total Orders | Order Status |Count|
+-----------+---------------+---------------+--------------+-----+
|Andrew |London |15 |Complete |8 |
|Andrew |London |15 |Pending |3 |
|Andrew |London |15 |Processing |4 |
|Andrew |London |15 |On-Hold |1 |
+-----------+---------------+---------------+--------------+-----+
Finally used your data as a CTE (common table expressions) and tested it. Cuctomer 1 has two PENDING_PAYMENT orders and 4 in total, all others have one order per status and 3 each in total:
with hivecustomers as
(
select 1 as cust_id , 'Richard' as cust_fname union all
select 2 as cust_id , 'Mary' as cust_fname union all
select 3 as cust_id , 'Ann' as cust_fname
),
hiveorders as
(
select 1 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 1 as ord_cust_id, 'CLOSED' as ord_stat union all
select 2 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 1 as ord_cust_id, 'PENDING_PAYMENT' as ord_stat union all
select 3 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 1 as ord_cust_id, 'COMPLETE' as ord_stat union all
select 4 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 1 as ord_cust_id, 'PENDING_PAYMENT' as ord_stat union all
select 21 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 2 as ord_cust_id, 'CLOSED' as ord_stat union all
select 22 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 2 as ord_cust_id, 'PENDING_PAYMENT' as ord_stat union all
select 23 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 2 as ord_cust_id, 'COMPLETE' as ord_stat union all
select 31 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 3 as ord_cust_id, 'CLOSED' as ord_stat union all
select 32 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 3 as ord_cust_id, 'PENDING_PAYMENT' as ord_stat union all
select 33 as ord_id, '2013-07-25 00:00:00.0' as ord_dt, 3 as ord_cust_id, 'COMPLETE' as ord_stat
)
select cust_fname, total_orders, order_status, count(*) Count
from
(
select c.cust_fname,
count(*) over(partition by c.cust_id) as total_orders,
o.ord_stat as Order_Status
from hivecustomers c left join hiveorders o on c.cust_id=o.ord_cust_id
)s
group by cust_fname, total_orders, order_status
Output:
OK
cust_fname total_orders order_status count
Ann 3 CLOSED 1
Ann 3 COMPLETE 1
Ann 3 PENDING_PAYMENT 1
Mary 3 CLOSED 1
Mary 3 COMPLETE 1
Mary 3 PENDING_PAYMENT 1
Richard 4 CLOSED 1
Richard 4 COMPLETE 1
Richard 4 PENDING_PAYMENT 2
Time taken: 40.692 seconds, Fetched: 9 row(s)
Just remove CTE and use normal tables instead.

Oracle - Assigning the correct Date from a Set

I have a table A like below
REGID | PKG_DESC | EVENT_DATE | IS_CON | IS_REN
-----------------------------------------------------
1234 | cc | 27-MAR-14 | 0 | 0
1234 | cc | 27-JUN-14 | 1 | 0
1234 | GUI | 27-MAR-14 | 0 | 0
1234 | GUI | 27-JUN-14 | 1 | 0
1234 | GUI | 27-SEPT-14 | 0 | 1
1234 | GUI | 27-SEPT-15 | 0 | 1
1234 | REMOTE | 27-MAR-14 | 0 | 0
1234 | REMOTE | 27-JUN-14 | 1 | 0
1234 | REMOTE | 27-SEPT-14 | 0 | 1
2431 | cc | 27-MAR-14 | 0 | 0
2431 | cc | 27-JUN-14 | 1 | 0
I have a query like below
select a.reg_id, b.sess_start_dt,
case when TRUNC(A.EVENT_DATE) - B.SESS_START_DT BETWEEN 0-30 THEN 'DAYS 0_30'
WHEN TRUNC(A.EVENT_DATE) - B.SESS_START_DT BETWEEN 31-60 THEN 'DAYS 31-60'
from tab a inner join tab b on a.reg_id = b.reg_id and a.is_ren = 1
union
select a.reg_id, b.sess_start_dt,
case when TRUNC(A.EVENT_DATE) - B.SESS_START_DT BETWEEN 0-30 THEN 'DAYS 0_30'
WHEN TRUNC(A.EVENT_DATE) - B.SESS_START_DT BETWEEN 31-60 THEN 'DAYS 31-60'
from tab a inner join tab b on a.reg_id = b.reg_id and a.is_con = 1
Tab B contains all the usage for each reg_id there will be 100's of records.. Sample of few are
REGID | SESS_START_DT
1234 | 27-Jan-14
1234 | 20-MAR-12
1234 | 27-MAR-12
1234 | 01-sept-14
1234 | 07-sept-14
1234 | 29-JUL-14
1234 | 03-AUG-14
1234 | 27-MAR-13
1234 | 27-MAR-12
1234 | 27-MAR-12
1234 | 27-MAR-12
1234 | 27-MAR-12
1234 | 27-MAR-12
1234 | 27-MAR-12
2431 | 20-JUN-14
The Above query needs to be corrected in a way like,
1) If the REG_ID is having at least one is_ren = 1 then that subscription should be considered as renewal subscription and needs to get the 30 days and 60 days usage from table B from his is_ren = 1 event_date. (for REGID 1234 only is_ren query should execute)
2) If multiple IS_REN = 1 are existing for each REGID then the usage needs to be taken 30 days and 60 days from table B with the MIN(event_date). in this case the usage should be taken from 27-SEPT-14 instead of 27-SEPT-15
3) If there is no IS_REN = 1 and there is IS_CON = 1 then it's considered as conversion and usage should be taken before 60 days from the converted date (for REGID 2431, usage needs to get 60 days back from 27-JUN-14{this is my event_date in the query})
The O/P should be like
REGID | EVENT_DATE | DAYS 0_30 | DAYS 31-60 | CODE
1234 | 27-SEPT-14 | 2 | 2 | REN
2431 | 27-JUL-14 | 1 | 0 | CON
If my assumptions in my Comment are correct, this may be what you need. Notice the order by clause in row_number() - first the rows with is_ren = 1, then the rows with is_ren = 0 and is_con = 1, then all the other rows, and within each group order by event_date ascending. This way, the top row (rn = 1), which is the only one I use in the outer query, will have is_ren = 1 with the earliest possible date, or if no is_ren = 1 then the row with is_con = 1 and the earliest date, or else just the earliest date. (In the last case, the CODE will be null: this means there were no is_ren = 1 and no is_con = 1 for that regid.
Not sure why you have 27-JUL-14 in the output for regid = 2431, that should be 27-JUN-14. Also, there are no four-letter months in Oracle ("SEPT"). The output shows dates using my session parameters; if you need to format the dates, use to_date(event_date, .....) with the desired date format model. Also, since the data you provided is just dates (with no time-of-day component), I didn't truncate anything; you may need to, if your real data has time-of-day components.
with
table_a ( regid, pkg_desc, event_date, is_con, is_ren ) as (
select 1234, 'cc' , to_date ('27-MAR-14', 'dd-MON-rr'), 0, 0 from dual union all
select 1234, 'cc' , to_date ('27-JUN-14', 'dd-MON-rr'), 1, 0 from dual union all
select 1234, 'GUI' , to_date ('27-MAR-14', 'dd-MON-rr'), 0, 0 from dual union all
select 1234, 'GUI' , to_date ('27-JUN-14', 'dd-MON-rr'), 1, 0 from dual union all
select 1234, 'GUI' , to_date ('27-SEP-14', 'dd-MON-rr'), 0, 1 from dual union all
select 1234, 'GUI' , to_date ('27-SEP-15', 'dd-MON-rr'), 0, 1 from dual union all
select 1234, 'REMOTE', to_date ('27-MAR-14', 'dd-MON-rr'), 0, 0 from dual union all
select 1234, 'REMOTE', to_date ('27-JUN-14', 'dd-MON-rr'), 1, 0 from dual union all
select 1234, 'REMOTE', to_date ('27-SEP-14', 'dd-MON-rr'), 0, 1 from dual union all
select 2431, 'cc' , to_date ('27-MAR-14', 'dd-MON-rr'), 0, 0 from dual union all
select 2431, 'cc' , to_date ('27-JUN-14', 'dd-MON-rr'), 1, 0 from dual
),
table_b ( regid, sess_start_dt ) as (
select 1234, to_date ('27-JAN-14', 'dd-MON-rr') from dual union all
select 1234, to_date ('20-MAR-12', 'dd-MON-rr') from dual union all
select 1234, to_date ('27-MAR-12', 'dd-MON-rr') from dual union all
select 1234, to_date ('01-SEP-14', 'dd-MON-rr') from dual union all
select 1234, to_date ('07-SEP-14', 'dd-MON-rr') from dual union all
select 1234, to_date ('29-JUL-14', 'dd-MON-rr') from dual union all
select 1234, to_date ('03-AUG-14', 'dd-MON-rr') from dual union all
select 1234, to_date ('27-MAR-13', 'dd-MON-rr') from dual union all
select 1234, to_date ('27-MAR-12', 'dd-MON-rr') from dual union all
select 1234, to_date ('27-MAR-12', 'dd-MON-rr') from dual union all
select 1234, to_date ('27-MAR-12', 'dd-MON-rr') from dual union all
select 1234, to_date ('27-MAR-12', 'dd-MON-rr') from dual union all
select 1234, to_date ('27-MAR-12', 'dd-MON-rr') from dual union all
select 1234, to_date ('27-MAR-12', 'dd-MON-rr') from dual union all
select 2431, to_date ('20-JUN-14', 'dd-MON-rr') from dual
),
prep ( regid, event_date, code, rn ) as (
select regid, event_date,
case when is_ren = 1 then 'REN' when is_con = 1 then 'CON' else null end,
row_number() over (partition by regid
order by case when is_ren = 1 then 0
when is_con = 1 then 1 else 2 end,
event_date)
from table_a
)
select p.regid, p.event_date,
count(case when b.sess_start_dt between p.event_date - 30 and p.event_date
then 1 end) as days_0_30,
count(case when b.sess_start_dt between p.event_date - 60 and p.event_date - 31
then 1 end) as days_31_60,
p.code
from prep p inner join table_b b on p.regid = b.regid
where rn = 1
group by p.regid, p.event_date, p.code
;
Output:
REGID EVENT_DATE DAYS_0_30 DAYS_31_60 COD
---------- ------------------- ---------- ---------- ---
1234 2014-09-27 00:00:00 2 2 REN
2431 2014-06-27 00:00:00 1 0 CON

Oracle SQL distinct count without outputting columns that make it distinct

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

how can use pivot on table such as datetime

I thought about writing a sql query.
I have a very simple table. There are two fields in this table.
CREATE TABLE [CHECKINOUT](
[USERID] [int] NOT NULL,
[CHECKTIME] [datetime] NOT NULL DEFAULT (getdate())
);GO
USERID CHECKTIME
1 2014-11-04 08:24:49.000
1 2014-11-03 16:57:00.000
1 2014-11-03 08:15:54.000
1 2014-10-28 12:57:58.000
1 2014-10-28 08:22:46.000
1 2014-10-24 16:58:33.000
1 2014-10-24 12:53:06.000
1 2014-10-24 08:21:38.000
1 2014-10-22 16:19:55.000
1 2014-10-21 08:26:21.000
There are sample table above.
I want to write this simple query using the pivot.
I wrote a pivot query but the value returned is null.
I wrote a query like this.
SELECT [USERID],[MORN_IN],[MORN_OUT],[NOON_IN],[NOON_OUT] FROM
(
SELECT [USERID], convert(NVARCHAR, ([CHECKTIME]), 104) as DATE_TIME FROM [CHECKINOUT]
) AS IN_OUT
PIVOT
(
MAX(DATE_TIME) --TO DATE
FOR DATE_TIME -- MY ROW COLUMN
IN
(
[MORN_IN],[MORN_OUT],[NOON_IN],[NOON_OUT] -- MY ROW COLUMN
)
) AS PIVOT_TABLE
incorrect query results--
USERID MORN_IN MORN_OUT NOON_IN NOON_OUT
1 NULL NULL NULL NULL
2 NULL NULL NULL NULL
3 NULL NULL NULL NULL
4 NULL NULL NULL NULL
5 NULL NULL NULL NULL
6 NULL NULL NULL NULL
7 NULL NULL NULL NULL
I want to do what?
the same user on the same day of their movements
I want to break into pieces.
for example:
00:00-11:00 =>MORN_IN
11:00-13:00 =>MORN_OUT(first record ONLY MIN(11:00-13:00))
12:00-15:00 =>NOON_IN (second record max(12:00-13:00) NOON_IN > MORN_OUT)
15:00-00:00 =>NOON_OUT
SELECT TOP 3 [USERID]
,[CHECKTIME]
FROM [CHECKINOUT] ORDER BY [USERID],[CHECKTIME] DESC
USERID my CHECKTIME
1 2014-10-24 16: 58: 33.000
1 2014-10-24 12: 53: 06,000
1 2014-10-24 08: 21: 38.000
now turn to the results of the pivot table (I can not do this part. but should return results like this)
USERID MORN_IN MORN_OUT NOON_IN NOON_OUT
1 2014-10-24 08: 21: 38.000 2014-10-24 12: 53: 06,000 NULL 2014-10-24 16: 58: 33.000
1
If time interval 13:00 - 16:30 is considered to be NOON_IN, then the following query:
SELECT DAY_DIVISION, [MORN_IN], [MORN_OUT], [NOON_IN], [NOON_OUT]
FROM
(SELECT CHECKTIME, CASE
WHEN CAST(CHECKTIME as time) >= '00:00:00' AND CAST(CHECKTIME as time) < '11:00:00' THEN 'MORN_IN'
WHEN CAST(CHECKTIME as time) >= '11:00:00' AND CAST(CHECKTIME as time) < '13:00:00' THEN 'MORN_OUT'
WHEN CAST(CHECKTIME as time) >= '13:00:00' AND CAST(CHECKTIME as time) < '16:30:00' THEN 'NOON_IN'
WHEN CAST(CHECKTIME as time) >= '16:30:00' THEN 'NOON_OUT'
END AS TIME_DIVISION,
RANK() OVER ( ORDER BY CAST(CHECKTIME as date) ASC) AS DAY_DIVISION
FROM CHECKINOUT) AS SourceTable
PIVOT
(
MAX(CHECKTIME)
FOR TIME_DIVISION IN ([MORN_IN], [MORN_OUT], [NOON_IN], [NOON_OUT])
) AS PivotTable;
yields this output:
DAY_DIVISION MORN_IN MORN_OUT NOON_IN NOON_OUT
------------------------------------------------------------------------------------
1 2014-10-21 08:26:21.000 NULL NULL NULL
2 NULL NULL 2014-10-22 16:19:55.000 NULL
3 2014-10-24 08:21:38.000 2014-10-24 12:54:06.000 NULL 2014-10-24 16:58:33.000
7 2014-10-28 08:22:46.000 2014-10-28 12:57:58.000 NULL NULL
9 2014-11-03 08:15:54.000 NULL NULL 2014-11-03 16:57:00.000
11 2014-11-04 08:24:49.000 NULL NULL NULL
Taking care of logins between 12:00 and 13:00 and multiple userIDs. (Tested on Oracle 11.2)
WITH
CheckInOutRaw(userID, checkTime) AS(
SELECT 1, '2014-11-04 08:24:49.000' FROM DUAL UNION ALL
SELECT 1, '2014-11-03 16:57:00.000' FROM DUAL UNION ALL
SELECT 1, '2014-11-03 08:15:54.000' FROM DUAL UNION ALL
SELECT 1, '2014-10-28 12:57:58.000' FROM DUAL UNION ALL
SELECT 1, '2014-10-28 08:22:46.000' FROM DUAL UNION ALL
SELECT 1, '2014-10-24 16:58:33.000' FROM DUAL UNION ALL
SELECT 1, '2014-10-24 12:53:06.000' FROM DUAL UNION ALL
SELECT 1, '2014-10-24 08:21:38.000' FROM DUAL UNION ALL
SELECT 1, '2014-10-22 16:19:55.000' FROM DUAL UNION ALL
SELECT 1, '2014-10-21 08:26:21.000' FROM DUAL UNION ALL
SELECT 2, '2014-11-04 08:24:49.000' FROM DUAL UNION ALL
SELECT 2, '2014-11-03 16:57:00.000' FROM DUAL UNION ALL
SELECT 2, '2014-11-03 08:15:54.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-29 11:07:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-29 12:07:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-29 16:57:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-28 11:07:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-28 12:07:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-28 16:57:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-28 08:22:46.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-27 12:57:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-27 12:07:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-27 16:57:58.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-27 08:22:46.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-24 16:58:33.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-24 12:53:06.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-24 08:21:38.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-22 13:19:55.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-22 16:19:55.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-21 08:26:21.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-20 12:19:55.000' FROM DUAL UNION ALL
SELECT 2, '2014-10-20 16:19:55.000' FROM DUAL
),
CheckInOutTemp AS (
SELECT
userID
, TO_TIMESTAMP(checkTime, 'YYYY-MM-DD HH24:MI:SSXFF3') checkTime
FROM
CheckInOutRaw
),
CheckInOut AS (
SELECT
userID
, checkTime
, TRUNC(checkTime) dt
, EXTRACT(HOUR FROM checkTime) h
, COUNT(CASE EXTRACT(HOUR FROM checkTime) WHEN 11 THEN 1 ELSE NULL END) OVER (PARTITION BY TRUNC(checkTime), userID) h11
, COUNT(CASE EXTRACT(HOUR FROM checkTime) WHEN 12 THEN 1 ELSE NULL END) OVER (PARTITION BY TRUNC(checkTime), userID) h12
FROM
CheckInOutTemp
),
S AS (
SELECT
userID
, checkTime
, dt
, CASE
WHEN h < 11 THEN 'MORN_IN'
WHEN h = 11 THEN 'MORN_OUT'
WHEN h11 = 1 AND h = 12 THEN 'NOON_IN'
WHEN h = 12 THEN 'MORN_OUT'
WHEN h < 16 THEN 'NOON_IN'
ELSE 'NOON_OUT'
END slot
FROM CheckInOut
WHERE NOT ((h = 12) AND (h12 = 2))
UNION ALL
SELECT
userID
, MIN(checkTime) checkTime
, dt
, 'MORN_OUT' slot
FROM CheckInOut
WHERE ((h = 12) AND (h12 = 2))
GROUP BY userID, dt
UNION ALL
SELECT
userID
, MAX(checkTime) checkTime
, dt
, 'NOON_IN' slot
FROM CheckInOut
WHERE ((h = 12) AND (h12 = 2))
GROUP BY userID, dt
)
SELECT
userID, TO_CHAR(dt, 'YYYY-MM-DD') dt, TO_CHAR(MORN_IN, 'HH24:MI:SS') morn_in, TO_CHAR(MORN_OUT, 'HH24:MI:SS') morn_out, TO_CHAR(NOON_IN, 'HH24:MI:SS') noon_in, TO_CHAR(NOON_OUT, 'HH24:MI:SS') noon_out
FROM (SELECT * FROM S PIVOT(MAX(checkTime) FOR slot IN ('MORN_IN' morn_in, 'MORN_OUT' morn_out, 'NOON_IN' noon_in, 'NOON_OUT' noon_out))) ORDER BY userID, DT DESC
;
Returns:
| USERID | DT | MORN_IN | MORN_OUT | NOON_IN | NOON_OUT |
|--------|------------|----------|----------|----------|----------|
| 1 | 2014-11-04 | 08:24:49 | (null) | (null) | (null) |
| 1 | 2014-11-03 | 08:15:54 | (null) | (null) | 16:57:00 |
| 1 | 2014-10-28 | 08:22:46 | 12:57:58 | (null) | (null) |
| 1 | 2014-10-24 | 08:21:38 | 12:53:06 | (null) | 16:58:33 |
| 1 | 2014-10-22 | (null) | (null) | (null) | 16:19:55 |
| 1 | 2014-10-21 | 08:26:21 | (null) | (null) | (null) |
| 2 | 2014-11-04 | 08:24:49 | (null) | (null) | (null) |
| 2 | 2014-11-03 | 08:15:54 | (null) | (null) | 16:57:00 |
| 2 | 2014-10-29 | (null) | 11:07:58 | 12:07:58 | 16:57:58 |
| 2 | 2014-10-28 | 08:22:46 | 11:07:58 | 12:07:58 | 16:57:58 |
| 2 | 2014-10-27 | 08:22:46 | 12:07:58 | 12:57:58 | 16:57:58 |
| 2 | 2014-10-24 | 08:21:38 | 12:53:06 | (null) | 16:58:33 |
| 2 | 2014-10-22 | (null) | (null) | 13:19:55 | 16:19:55 |
| 2 | 2014-10-21 | 08:26:21 | (null) | (null) | (null) |
| 2 | 2014-10-20 | (null) | 12:19:55 | (null) | 16:19:55 |
Looking at
| 2 | 2014-10-20 | (null) | 12:19:55 | (null) | 16:19:55 |
it does probably not make a lot of sense - but seems to be in the line with the specification.
SQL Fiddle