I have monthly agents' sales data. I need to get the first 25 days sales count and last 5 days columns.
How to get in separately.
I have below table
Agent_ID Date Device
2343 1/1/2019 33330
3245 1/1/2019 43554
2343 5/1/2019 46665
3245 10/1/2019 78900
2343 15/1/2019 55678
2343 26/1/2019 45678
3245 28/1/2019 48900
2343 30/1/2019 56710
5645 12/1/2019 33067
5645 15/1/2019 44890
2121 31/1/2019 55810
I need to get this below output table
Agent_ID first_25days_sale_count Last_5days_sale_count
2343 3 2
3245 2 1
5645 2 0
2121 0 1
Some months have 28, 29 or 31 days so naively using "first 25 days" and "last 5 days" may lead to either double counting (i.e. days 24 and 25 when February has 28 days) or not counting some days (i.e. day 26 when the the month has 31 days). You should decide whether you want to count:
The first 25 days and then the remaining 3-6 days after that; or
The last 5 days and then the 23-26 days before that.
Whichever you chose, you can use conditional aggregation:
SELECT agent_id,
COUNT(
CASE
WHEN EXTRACT( DAY FROM "Date" ) <= 25
THEN 1
END
) AS first_25days_sale_count,
COUNT(
CASE
WHEN EXTRACT( DAY FROM "Date" ) > 25
THEN 1
END
) AS after_first_25days_sale_count,
COUNT(
CASE
WHEN "Date" < TRUNC( LAST_DAY( "Date" ) ) - INTERVAL '4' DAY
THEN 1
END
) AS not_last_5days_sale_count,
COUNT(
CASE
WHEN "Date" >= TRUNC( LAST_DAY( "Date" ) ) - INTERVAL '4' DAY
THEN 1
END
) AS last_5days_sale_count
FROM your_table
GROUP BY agent_id;
So, for your sample data:
CREATE TABLE your_table ( Agent_ID, "Date", Device ) AS
SELECT 2343, DATE '2019-01-01', 33330 FROM DUAL UNION ALL
SELECT 3245, DATE '2019-01-01', 43554 FROM DUAL UNION ALL
SELECT 2343, DATE '2019-01-05', 46665 FROM DUAL UNION ALL
SELECT 3245, DATE '2019-01-10', 78900 FROM DUAL UNION ALL
SELECT 2343, DATE '2019-01-15', 55678 FROM DUAL UNION ALL
SELECT 2343, DATE '2019-01-26', 45678 FROM DUAL UNION ALL
SELECT 3245, DATE '2019-01-29', 48900 FROM DUAL UNION ALL
SELECT 2343, DATE '2019-01-30', 56710 FROM DUAL UNION ALL
SELECT 5645, DATE '2019-01-12', 33067 FROM DUAL UNION ALL
SELECT 5645, DATE '2019-01-15', 44890 FROM DUAL UNION ALL
SELECT 2121, DATE '2019-01-31', 55810 FROM DUAL;
This outputs:
AGENT_ID | FIRST_25DAYS_SALE_COUNT | AFTER_FIRST_25DAYS_SALE_COUNT | NOT_LAST_5DAYS_SALE_COUNT | LAST_5DAYS_SALE_COUNT
-------: | ----------------------: | ----------------------------: | ------------------------: | --------------------:
3245 | 2 | 1 | 2 | 1
2121 | 0 | 1 | 0 | 1
5645 | 2 | 0 | 2 | 0
2343 | 3 | 2 | 4 | 1
db<>fiddle here
I am selecting filial expenditures in US dollar for a particular date. But I need to convert it into Won currency for that date. Currencies`s value changes at any time according to US dollar. Currency history is in table of V_CURRENCY. I need to multiply dollar to that amount and show in Won. My query is below and giving an error. Error is [22008][1861] ORA-01861. Mismatch of rows.
with cte as (
select t.filial_code,
t.modified_by as emp_code,
sum(t.sum_oper) as summa,
to_char(t.oper_date, 'YYYY-MM-DD') as operation_date
from OPERS t,
DEP_OPERS d
WHERE
And t.modified_by = 213
And t.filial_code = '00116'
And d.currency_code = 840
And t.oper_date >= to_date('07.01.2020', 'DD.MM.YYYY')
And t.oper_date < to_date('11.01.2020', 'DD.MM.YYYY')
group by to_char(t.oper_date, 'YYYY-MM-DD'), t.filial_code, t.modified_by
) select cte.filial_code,cte.emp_code,cte.summa * (select equival from V_CURRENCY
where date_activ = (select max(date_activ)
from V_CURRENCY
where date_activ <= cte.operation_date) and code = 840) as summa,cte.operation_date from cte;
From cte I am taking below result :
FILIAL_CODE | EMP_CODE | SUMMA | OPERATION_DATE
-----------------------------------------------
00116 | 213 | 40000 | 2020-01-14
00116 | 213 | 6000 | 2020-01-10
00116 | 213 | 2800 | 2020-01-06
My V_CURRENCY table is like below:
CODE | DATE_ACTIV | EQUIVAL|
--------------------------------
840 | 2020-01-13 00:00:00 | 576.97
840 | 2020-01-07 00:00:00 | 2008.54
840 | 2020-01-06 00:00:00 | 1941.91
840 | 2019-12-22 00:00:00 | 301.62
190 | 2020-01-13 00:00:00 | 1200.97
270 | 2020-01-13 00:00:00 | 2300.21
800 | 2019-12-22 00:00:00 | 100.62
I need to multiply equival from table V_CURRENCY in date 2020-01-13 00:00:00 to my cte result SUMMA for OPERATION_DATE 2020-01-14, means that 4000 * 576.97, cause OPERATION_DATE is closest one to currency change date. But when DATE_ACTIV exists for date 2020-01-06 then 2800 * 1941.91. I only need curreny value whose code is 840.
My last result should look like :
FILIAL_CODE | EMP_CODE | SUMMA | OPERATION_DATE
-----------------------------------------------
00116 | 213 | 40000 * 576.97 | 2020-01-14
00116 | 213 | 6000 * 2008.54 | 2020-01-10
00116 | 213 | 2800 * 1941.91 | 2020-01-06
Any response appreciated. Thanks in advance.
Use the LEAD analytic function to find the date the currency conversion is valid up until and then join the tables on the range between the start and end dates the currency is valid for:
SELECT y.filial_code,
y.emp_code,
y.summa * c.equival AS summa,
y.operation_date
FROM your_cte y
INNER JOIN (
SELECT c.*,
LEAD( DATE_ACTIV, 1, SYSDATE )
OVER ( PARTITION BY code ORDER BY date_activ )
AS DATE_FINISHED
FROM v_currency c
WHERE currency_code = 840
) c
ON ( y.operation_date >= c.date_activ
AND y.operation_date < c.date_finished )
Outputs:
FILIAL_CODE | EMP_CODE | SUMMA | OPERATION_DATE
:---------- | -------: | -------: | :-------------
00116 | 213 | 23078800 | 14-JAN-20
00116 | 213 | 12051240 | 10-JAN-20
00116 | 213 | 5437348 | 06-JAN-20
db<>fiddle here
As an aside, your CTE doesn't need to convert dates to strings and can use date literals and a modern ANSI join (rather than legacy comma join):
with cte ( filial_code, emp_code, summa, operation_date ) as (
SELECT t.filial_code,
t.modified_by,
sum(t.sum_oper),
t.oper_date
from OPERS t
CROSS JOIN
DEP_OPERS d
WHERE t.modified_by = 213
AND t.filial_code = '00116'
AND d.currency_code = 840
AND t.oper_date >= DATE '2020-01-07'
AND t.oper_date < DATE '2020-01-11'
GROUP BY t.oper_date,
t.filial_code,
t.modified_by
)
...
and you don't even need the CTE:
SELECT t.filial_code,
t.modified_by AS emp_code,
SUM(t.sum_oper * c.equival) AS summa,
t.oper_date AS operation_date
FROM OPERS t
CROSS JOIN
DEP_OPERS d
INNER JOIN (
SELECT c.*,
LEAD( DATE_ACTIV, 1, SYSDATE )
OVER ( PARTITION BY code ORDER BY date_activ )
AS DATE_FINISHED
FROM v_currency c
) c
ON ( t.oper_date >= c.date_activ
AND t.oper_date < c.date_finished
AND d.currency_code = c.currency_code )
WHERE t.modified_by = 213
AND t.filial_code = '00116'
AND d.currency_code = 840
AND t.oper_date >= DATE '2020-01-07'
AND t.oper_date < DATE '2020-01-11'
GROUP BY t.oper_date,
t.filial_code,
t.modified_by
I've trying to get this query work efficiently over the past two days. I've learn more about Oracle Index behavior that I think I'm confused at this point what is supposed to work and what doesn't.
Basically, the query is summing up values and comparing to values from yesterday and last week.
I've played around with breaking it down, I've toyed in my mind analytic queries and changing order of indices but nothing seems to work. All my test has been on a table with 500K rows, as soon as I run it on a table with 20 Million rows it just takes forever.
Any help is greatly appreciated.
I modified the original post to help you help me. :)
CREATE TABLE TABLE_1
(ORDER_LINE_ID NUMBER, OFFSET NUMBER, BREAK_ID NUMBER, ZONE NUMBER, NETWORK NUMBER, HOUR_OF_DAY NUMBER, START_TIME DATE, END_TIME DATE, SUCCESS NUMBER
CONSTRAINT "TABLE_1_PK" PRIMARY KEY (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, HOUR_OF_DAY))
-- SUCCESS is already aggregated during the insert
-- These are last week's records
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (1,0,1, 1, 1, 2016042001,'04/20/2016 00:00:00', '04/20/2016 02:00:00', 1);
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (1,30,1, 1, 1, 2016042001,'04/20/2016 00:00:00', '04/20/2016 02:00:00', 2);
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (2,0,1, 1, 1, 2016042001,'04/20/2016 00:00:00', '04/20/2016 02:00:00', 1);
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (2,30,1, 1, 1, 2016042001,'04/20/2016 00:00:00', '04/20/2016 02:00:00', 1);
-- These are yesterday's records
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (3,0,1, 1, 1, 2016042601,'04/26/2016 00:00:00', '04/26/2016 02:00:00', 1);
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (3,30,1, 1, 1, 2016042601,'04/26/2016 00:00:00', '04/26/2016 02:00:00', 2);
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (4,0,1, 1, 1, 2016042601,'04/26/2016 00:00:00', '04/26/2016 02:00:00', 1);
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (4,30,1, 1, 1, 2016042601,'04/26/2016 00:00:00', '04/26/2016 02:00:00', 1);
-- This is today's records
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (5,0,1, 1, 1, 2016042701,'04/27/2016 00:00:00', '04/27/2016 02:00:00', 1);
INSERT INTO TABLE_1 (ORDER_LINE_ID, OFFSET, BREAK_ID, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME, SUCCESS)
VALUES (5,30,1, 1, 1, 2016042701,'04/27/2016 00:00:00', '04/27/2016 02:00:00', 1);
-- Original twice join query
SELECT BREAK_ID, ORDER_LINE_ID, HOUR_OF_DAY, OFFSET, ZONE, NETWORK, START_TIME, END_TIME, SUM(SUCCESS), SUM(YESTERDAY_SUCCESS), SUM(LAST_WEEK_SUCCESS)
FROM TABLE_1 CURRENT_DAY
LEFT OUTER JOIN (
SELECT SUM(SUCCESS) YESTERDAY_SUCCESS, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME FROM TABLE_1
GROUP BY ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME
) YESTERDAY
ON YESTERDAY.START_TIME + 1 = CURRENT_DAY.START_TIME
AND YESTERDAY.END_TIME + 1 = CURRENT_DAY.END_TIME
AND YESTERDAY.HOUR_OF_DAY = CURRENT_DAY.HOUR_OF_DAY
AND YESTERDAY.NETWORK = CURRENT_DAY.NETWORK
AND YESTERDAY.ZONE = CURRENT_DAY.ZONE
LEFT OUTER JOIN (
SELECT SUM(SUCCESS) LAST_WEEK_SUCCESS, ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME FROM TABLE_1
GROUP BY ZONE, NETWORK, HOUR_OF_DAY, START_TIME, END_TIME
) LAST_WEEK
ON YESTERDAY.START_TIME + 7 = CURRENT_DAY.START_TIME
AND YESTERDAY.END_TIME + 7 = CURRENT_DAY.END_TIME
AND YESTERDAY.HOUR_OF_DAY = CURRENT_DAY.HOUR_OF_DAY
AND YESTERDAY.NETWORK = CURRENT_DAY.NETWORK
AND YESTERDAY.ZONE = CURRENT_DAY.ZONE
GROUP BY BREAK_ID, ORDER_LINE_ID, HOUR_OF_DAY, OFFSET, ZONE, NETWORK, START_TIME, END_TIME;
-- Using Analytic Query (thank you to MT0)
SELECT BREAK_ID, ORDER_LINE_ID, HOUR_OF_DAY, OFFSET, ZONE, NETWORK, START_TIME, END_TIME, SUM(SUCCESS), SUM(YESTERDAY_SUCCESS), SUM(LAST_WEEK_SUCCESS)
FROM (
SUM( SUCCESS )
OVER ( PARTITION BY ZONE, NETWORK, HOUR_OF_DAY, TO_CHAR(START_TIME, 'HH24:MI:SS'), TO_CHAR(END_TIME, 'HH24:MI:SS')
ORDER BY START_TIME
RANGE BETWEEN INTERVAL '1' DAY PRECDEDING AND INTERVAL '1' DAY PRECEDING
) AS YESTERDAY_SUCCESS,
SUM ( SUCCESS )
OVER ( PARTITION BY ZONE, NETWORK, HOUR_OF_DAY, TO_CHAR(START_TIME, 'HH24:MI:SS'), TO_CHAR(END_TIME, 'HH24:MI:SS')
ORDER BY START_TIME
RANGE BETWEEN INTERVAL '7' DAY PRECDEDING AND INTERVAL '7' DAY PRECEDING
) AS LAST_WEEK_SUCCESS
FROM TABLE_1
) T1
WHERE SYSDATE - INTERVAL '12' HOUR <= START_TIME
AND START_TIME < SYSDATE - INTERVAL '1' HOUR
GROUP BY BREAK_ID, ORDER_LINE_ID, HOUR_OF_DAY, OFFSET, ZONE, NETWORK, START_TIME, END_TIME;
I must say thank you for the help to bring this question up to something I hope is more understandable. Everything works as expected but performance could use some tuning.
1.8 seconds on a table with 500K rows
400 seconds on a table with 20 million rows
i also want to add some Execution Plans provided by Oracle. I'm having trouble tuning performance.
-- using twice self join
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | O/1/M |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 50 |00:00:00.84 | 99875 | 217 | 1705 | | | |
| 1 | HASH GROUP BY | | 1 | 6711 | 50 |00:00:00.84 | 99875 | 217 | 1705 | 1616K| 995K| |
|* 2 | FILTER | | 1 | | 119K|00:00:00.65 | 99875 | 0 | 0 | | | |
| 3 | NESTED LOOPS OUTER | | 1 | 54M| 119K|00:00:00.64 | 99875 | 0 | 0 | | | |
|* 4 | HASH JOIN OUTER | | 1 | 109 | 119K|00:00:00.52 | 99875 | 0 | 0 | 13M| 2093K| 1/0/0|
| 5 | TABLE ACCESS BY INDEX ROWID| TABLE_1_IDX | 1 | 109 | 119K|00:00:00.14 | 85908 | 0 | 0 | | | |
|* 6 | INDEX RANGE SCAN | START_TIME_IDX | 1 | 109 | 119K|00:00:00.02 | 320 | 0 | 0 | | | |
| 7 | VIEW | | 1 | 1250 | 29311 |00:00:00.23 | 13967 | 0 | 0 | | | |
| 8 | HASH GROUP BY | | 1 | 1250 | 29311 |00:00:00.22 | 13967 | 0 | 0 | 3008K| 1094K| 1/0/0|
|* 9 | FILTER | | 1 | | 88627 |00:00:00.20 | 13967 | 0 | 0 | | | |
|* 10 | TABLE ACCESS FULL | TABLE_1 | 1 | 1250 | 88627 |00:00:00.19 | 13967 | 0 | 0 | | | |
| 11 | VIEW | | 119K| 499K| 0 |00:00:00.10 | 0 | 0 | 0 | | | |
| 12 | SORT GROUP BY | | 119K| 499K| 0 |00:00:00.08 | 0 | 0 | 0 | 1024 | 1024 | 1/0/0|
|* 13 | FILTER | | 119K| | 0 |00:00:00.02 | 0 | 0 | 0 | | | |
| 14 | TABLE ACCESS FULL | TABLE_1 | 0 | 499K| 0 |00:00:00.01 | 0 | 0 | 0 | | | |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(SYSDATE#!-17<SYSDATE#!-16)
4 - access("YESTERDAY"."ZONE"="T1"."ZONE" AND "YESTERDAY"."NETWORK"="T1"."NETWORK" AND "YESTERDAY"."HOUR_OF_DAY"="T1"."HOUR_OF_DAY"
AND "T1"."END_TIME"=INTERNAL_FUNCTION("YESTERDAY"."END_TIME")+1 AND
"T1"."START_TIME"=INTERNAL_FUNCTION("YESTERDAY"."START_TIME")+1)
6 - access("T1"."START_TIME">=SYSDATE#!-17 AND "T1"."START_TIME"<SYSDATE#!-16)
9 - filter(SYSDATE#!-17<SYSDATE#!-16)
10 - filter((INTERNAL_FUNCTION("START_TIME")+1>=SYSDATE#!-17 AND INTERNAL_FUNCTION("START_TIME")+1<SYSDATE#!-16))
13 - filter(("YESTERDAY"."ZONE"="T1"."ZONE" AND "YESTERDAY"."NETWORK"="T1"."NETWORK" AND "YESTERDAY"."HOUR_OF_DAY"="T1"."HOUR_OF_DAY"
AND "T1"."END_TIME"=INTERNAL_FUNCTION("YESTERDAY"."END_TIME")+7 AND
"T1"."START_TIME"=INTERNAL_FUNCTION("YESTERDAY"."START_TIME")+7))
Another execution plan using Analytic Query (thank again to MT0)
-- using analytic query
-------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | O/1/M |
-------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 50 |00:00:01.51 | 13967 | | | |
| 1 | HASH GROUP BY | | 1 | 499K| 50 |00:00:01.51 | 13967 | 98M| 7788K| |
|* 2 | VIEW | | 1 | 499K| 119K|00:00:01.15 | 13967 | | | |
| 3 | WINDOW SORT | | 1 | 499K| 499K|00:00:01.43 | 13967 | 66M| 2823K| 1/0/0|
|* 4 | FILTER | | 1 | | 499K|00:00:00.16 | 13967 | | | |
| 5 | TABLE ACCESS FULL| TABLE_1 | 1 | 499K| 499K|00:00:00.12 | 13967 | | | |
-------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("T1"."START_TIME">=SYSDATE#!-INTERVAL'+17 00:00:00' DAY(2) TO SECOND(0) AND
"T1"."START_TIME"<SYSDATE#!-INTERVAL'+16 00:00:00' DAY(2) TO SECOND(0)))
4 - filter(SYSDATE#!-INTERVAL'+17 00:00:00' DAY(2) TO SECOND(0)<SYSDATE#!-INTERVAL'+16 00:00:00' DAY(2) TO
SECOND(0))
As you can see, I added an index on start_time which self-Join query benefits from but estimates vs actuals are off. Where Analytic Query just decides it wants nothing to do with the index. Any ideas, points of references or help is greatly appreciated. Thanks in advance, everyone.
It is unclear why you are joining only when there are rows with exactly the same time today and yesterday (or last week) but if you just want the rows that are between certain times then you can eliminate all the self-joins and do:
SELECT order_line,
zone,
network,
sum(
CASE WHEN SYSDATE - INTERVAL '12' HOUR <= start_time
AND start_time < SYSDATE - INTERVAL '1' HOUR
THEN success
END
) AS total_successes_today,
sum(
CASE WHEN SYSDATE - INTERVAL '12' HOUR <= start_time
AND start_time < SYSDATE - INTERVAL '1' HOUR
THEN error
END
) AS total_errors_today,
sum(
CASE WHEN SYSDATE - INTERVAL '36' HOUR <= start_time
AND start_time < SYSDATE - INTERVAL '25' HOUR
THEN success
END
) AS total_successes_yesterday,
sum(
CASE WHEN SYSDATE - INTERVAL '180' HOUR <= start_time
AND start_time < SYSDATE - INTERVAL '169' HOUR
THEN success
END
) AS total_successes_last_week
FROM table_1
WHERE ( SYSDATE - INTERVAL '12' HOUR <= start_time
AND start_time < SYSDATE - INTERVAL '1' HOUR ) -- today
OR ( SYSDATE - INTERVAL '36' HOUR <= start_time
AND start_time < SYSDATE - INTERVAL '25' HOUR ) -- yesterday = today + 24 hours
OR ( SYSDATE - INTERVAL '180' HOUR <= start_time
AND start_time < SYSDATE - INTERVAL '169' HOUR ) -- last week = today + 7*24 hours
However, if you do want to keep the join on the start- and end-times then you could use an analytic query:
SELECT order_line,
zone,
network,
SUM( success ),
SUM( error ),
SUM( yesterday_success ),
SUM( last_week_success )
FROM (
SELECT t.*,
SUM( success )
OVER ( PARTITION BY id,
TO_CHAR( start_time, 'HH24:MI:SS' ),
TO_CHAR( end_time, 'HH24:MI:SS' )
ORDER BY start_time
RANGE BETWEEN INTERVAL '1' DAY PRECEDING AND INTERVAL '1' DAY PRECEDING
) AS yesterday_success,
SUM( success )
OVER ( PARTITION BY id,
TO_CHAR( start_time, 'HH24:MI:SS' ),
TO_CHAR( end_time, 'HH24:MI:SS' )
ORDER BY start_time
RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND INTERVAL '7' DAY PRECEDING
) AS last_week_success
FROM TABLE_1 t
)
WHERE SYSDATE - INTERVAL '12' HOUR <= start_time
AND start_time < SYSDATE - INTERVAL '1' HOUR
GROUP BY
order_line,
zone,
network
ORDER BY
order_line,
zone,
network
You can look at whether you would get speed improvements by using function-based indexes on TO_CHAR( start_time, 'HH24:MI:SS' ) and TO_CHAR( end_time, 'HH24:MI:SS' ).
I'll preemptively say I search the other questions and online, however could not find it. Whether that be poor wording choice on my part, or otherwise.
I have a ticketing queue and searching through it's history. Column "Group" will contain the group name that owns the ticket upon a transfer action. There are many other actions, such as just adding comments to the ticket. I am only interested if the most recent value in the column (ignoring nulls) if it is "QUEUE_X".
I know this is improper because of the group-function but this is logically how I view it:
select
*
from
ticket_history
where
max(group) = 'QUEUE_X'
order by
date
;
I don't want to strictly do where group = 'X' because tickets can be transferred around a lot and I only care about the tickets in my queue at the current time. Also, I cannot find if or where the original developer put a CURRENT_QUEUE-like column, so out of luck the easy way. Don't take it too literal, just wanted to illustrate the null values in GROUP and I'd like the most recent value to equal Queue_X
Example table data of a ticket I would NOT want (though if the query occured at 12:12, I would have):
STRT_DATE | PERSON | GROUP | TICKET_NUM | END_DATE
12/3/15 12:00 | Ted | Queue_Y | 111111 | 12/3/15 12:05
12/3/15 12:05 | Bob | | 111111 | 12/3/15 12:10
12/3/15 12:10 | Ted | Queue_Y | 222222 | 12/3/15 12:45
12/3/15 12:10 | Bob | Queue_X | 111111 | 12/3/15 12:15
12/3/15 12:15 | Bob | | 222222 | 12/3/15 12:45
12/3/15 12:15 | Mary | Queue_Y | 111111 | 12/3/15 12:25
12/3/15 12:25 | Ted | | 222222 | 12/3/15 12:35
12/3/15 12:35 | Ted | | 333333 | 12/3/15 12:45
12/3/15 12:35 | Bob | Queue_X | 333333 | 12/3/15 12:45
12/3/15 12:45 | Ted | | 111111 | 12/3/15 12:55
12/3/15 12:55 | Bob | Queue_X | 111111 | 12/3/15 12:56
Desired Results:
12/3/15 12:35 | Bob | Queue_X | 333333 | 12/3/15 12:45
12/3/15 12:55 | Bob | Queue_X | 111111 | 12/3/15 12:56
(Still in Queue_Y):
12/3/15 12:10 | Ted | Queue_Y | 222222 | 12/3/15 12:45
Thank you in advance.
EDIT: Added more tickets and an additional member to Queue_Y (so there is not a 1-1 relationship between queue and person)
not totally sure what you are trying to accomplish but I think you want something like dense_rank() here is one I put together mytable represents your data, t1 does the dense rank check
ok here is the query running after 12:15 and no data is returned.
WITH mytable
AS (SELECT TO_DATE ('12/3/15 12:00', 'mm/dd/yy hh:mi') AS strt_dt,
'Ted' AS person,
'Queue_Y' AS grp,
123456 AS ticket_num
FROM DUAL
UNION ALL
SELECT TO_DATE ('12/3/15 12:05', 'mm/dd/yy hh:mi') AS strt_dt,
'Bob',
NULL,
123456
FROM DUAL
UNION ALL
SELECT TO_DATE ('12/3/15 12:10', 'mm/dd/yy hh:mi') AS strt_dt,
'Bob',
'Queue_X',
123456
FROM DUAL
UNION ALL
SELECT TO_DATE ('12/3/15 12:15', 'mm/dd/yy hh:mi') AS strt_dt,
'Ted',
'Queue_Y',
123456
FROM DUAL),
t2
AS (SELECT mytable.*,
DENSE_RANK ()
OVER (PARTITION BY ticket_num ORDER BY strt_dt DESC)
AS test_for_Q
FROM mytable)
SELECT strt_dt, person, grp, ticket_num
FROM t2
WHERE ticket_num IN (SELECT ticket_num
FROM t2
WHERE test_for_Q = 1 AND Grp = 'Queue_X')
now here is the query running at 12:12 and you get data back.
WITH mytable
AS (SELECT TO_DATE ('12/3/15 12:00', 'mm/dd/yy hh:mi') AS strt_dt,
'Ted' AS person,
'Queue_Y' AS grp,
123456 AS ticket_num
FROM DUAL
UNION ALL
SELECT TO_DATE ('12/3/15 12:05', 'mm/dd/yy hh:mi') AS strt_dt,
'Bob',
NULL,
123456
FROM DUAL
UNION ALL
SELECT TO_DATE ('12/3/15 12:10', 'mm/dd/yy hh:mi') AS strt_dt,
'Bob',
'Queue_X',
123456
FROM DUAL
-- UNION ALL
-- SELECT TO_DATE ('12/3/15 12:15', 'mm/dd/yy hh:mi') AS strt_dt,
-- 'Ted',
-- 'Queue_Y',
-- 123456
-- FROM DUAL
) ,
t2
AS (SELECT mytable.*,
DENSE_RANK ()
OVER (PARTITION BY ticket_num ORDER BY strt_dt DESC)
AS test_for_Q
FROM mytable)
SELECT strt_dt, person, grp, ticket_num
FROM t2
WHERE ticket_num IN (SELECT ticket_num
FROM t2
WHERE test_for_Q = 1 AND Grp = 'Queue_X')
results
STRT_DT,PERSON,GRP,TICKET_NUM
12/3/2015 12:10:00 PM,Bob,Queue_X,123456
12/3/2015 12:05:00 PM,Bob,,123456
12/3/2015 12:00:00 PM,Ted,Queue_Y,123456
If I understand your problem right your query would be:
select a.*
from ticket_history a
INNER JOIN ( select PERSON, GROUP, max(STRT_DATE) as maxdt
from ticket_history
where group = 'Queue_X'
group by PERSON, GROUP ) b
ON ( a.person = b.person
and a.group = b.group
and a.STRT_DATE = b.maxdt )
order by a.STRT_DATE desc
Please see if it is what you need, otherwise let me know.
Try this (edited):
select strt_date, person, group, ticket_num, end_date
from ticket_history
where (rowid, end_date) IN (select rowid, max(end_date)
from ticket_history
where group = 'QUEUE_X'
group by rowid)
order by end_date;
This will reflect what you show in your desired output.