How to get the earliest date of the lastmodifier? - oracle

I choose to pickup the earliest date and also the same row of another column which is lastmodifier. Is this possible to get the same row data just like vlookup. when I MIN(DATE) and will lookup the other column same row 's value.
I have try to get the min(date) and group by lastmodifier. However, I don't know which lastmodifier does the script pick.
with CASECODESTATS (ORDBATCH,PO,EARLIEST,OPERATOR,count1,count2) as
(
select substr(code,1,15),substr(code,1,14),MIN(LSTUPDTIME),LSTMODIFIER,COUNT(c.code) ,0
from casecode c
where c.state='REVIEWED'
group by substr(code,1,15),LSTMODIFIER,substr(code,1,14)
union all
select substr(code,1,15),substr(code,1,14),MIN(LSTUPDTIME),LSTMODIFIER,0,COUNT(c.code)
from casecode c
where c.state ='WAREHOUSE RECEIVE'
group by substr(code,1,15),LSTMODIFIER,substr(code,1,14)
)
select ORDBATCH ORBATCH,sum(count1) REVIEWED ,sum(count2) WAREHOUSERECIEVE,MIN(EARLIEST) EARLIESTDATE,OPERATOR LSTMODIFIER,PO ORDERNUM from CASECODESTATS
where 1=1
group by ORDBATCH,OPERATOR,PO
order by ORDBATCH
I want to select the 1st lastmodifier in every ordernumber.

I am not sure if I understood correctly, sample data and expected output would be very helpful in such question. But I think you need this:
select substr(code, 1, 2) ordbatch, substr(code, 1, 1) ordernum, min(lstupdtime) earliest,
min(lstmodifier) keep (dense_rank first order by lstupdtime) lstmodifier,
count(case state when 'REVIEWED' then 1 end) reviewed,
count(case state when 'WAREHOUSE RECEIVE' then 1 end) warehouse
from casecode
where state in ('REVIEWED', 'WAREHOUSE RECEIVE')
group by substr(code,1,2), substr(code,1,1)
First: you do not need union, use conditional count with case. But the answer to your main question is min ... keep ... first. It finds value of some column (lstmodifier) where value of the other column (lstupdtime) is the lowest. min means that if two operators meets criteria we have to pick someone so we take first alphabetically. I don't know what you want to do in such situation, depending on that different solutions are posibble, for instance with rank and listagg.
Here is the example:
with casecode(code, state, lstupdtime, lstmodifier) as (
select 'A1', 'REVIEWED', date '2018-12-25', 'Clark' from dual union all
select 'A1', 'OTHER', date '2018-12-25', 'Clark' from dual union all
select 'A1', 'WAREHOUSE RECEIVE', date '2018-12-25', 'Clark' from dual union all
select 'A1', 'WAREHOUSE RECEIVE', date '2018-12-24', 'Jones' from dual union all
select 'B1', 'WAREHOUSE RECEIVE', date '2018-12-25', 'Clark' from dual union all
select 'B2', 'WAREHOUSE RECEIVE', date '2018-12-25', 'Clark' from dual
)
select substr(code, 1, 2) ordbatch, substr(code, 1, 1) ordernum, min(lstupdtime) earliest,
min(lstmodifier) keep (dense_rank first order by lstupdtime) lstmodifier,
count(case state when 'REVIEWED' then 1 end) reviewed,
count(case state when 'WAREHOUSE RECEIVE' then 1 end) warehouse
from casecode
where state in ('REVIEWED', 'WAREHOUSE RECEIVE')
group by substr(code,1,2), substr(code,1,1)
I used shorter substr for code manipulation to make things clear, use 14 and 15 instead. Jones is picked, because his lstupdtime is the lowest:
ORDBATCH ORDERNUM EARLIEST LSTMODIFIER REVIEWED WAREHOUSE
-------- -------- ----------- ----------- ---------- ----------
A1 A 2018-12-24 Jones 1 2
B1 B 2018-12-25 Clark 0 1
B2 B 2018-12-25 Clark 0 1

Related

select minimum date after maximum gap oracle

I have data for a member like below
EFF_DT-Term_dt
1/1/13-7/31/14
1/1/15-3/31/15
5/1/15-5/31/15
6/1/15-12/31/15
1/1/16-12/31/16
Here there are 2 gaps - after 7/31/14 and 3/31/15. I want to select the row 5/1/15-5/31/15 as it is the minimum date after maximum gap. I tried using
select ( FIRST_VALUE(EFF_DT) OVER (PARTITION BY MemberID ORDER BY FLAG DESC) AS CUR_EFF_DT)
from
(
select EFF_DT,
CASE WHEN LAG(TERM_DT, 1) OVER (PARTITION BY MemberID ORDER BY TERM_DT) = EFF_DT - 1 THEN 0
ELSE sequence.nextval
END AS FLAG
from effective_dates_table).
This is giving correct result, but i don't want to use sequence Is there any other easiest way to do this?
Here's one way... compute the differences using the analytic LAG() function, then group by member_id and use the aggregate LAST() function.
NOTE: there may be more than one pair of rows with the same, greatest gap between term_dt and the following eff_dt. You must clarify which row should be selected if that happens. The solution below picks the earliest occurrence (if this happens). If you want the latest occurrence, change MIN to MAX. If you want something else, just say what the requirement is.
with
inputs ( member_id, eff_dt, term_dt ) as (
select 101, to_date('1/1/13', 'mm/dd/yy'), to_date('7/31/14' , 'mm/dd/yy') from dual union all
select 101, to_date('1/1/15', 'mm/dd/yy'), to_date('3/31/15' , 'mm/dd/yy') from dual union all
select 101, to_date('5/1/15', 'mm/dd/yy'), to_date('5/31/15' , 'mm/dd/yy') from dual union all
select 101, to_date('6/1/15', 'mm/dd/yy'), to_date('12/31/15', 'mm/dd/yy') from dual union all
select 101, to_date('1/1/16', 'mm/dd/yy'), to_date('12/31/16', 'mm/dd/yy') from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- Use your actual table and column names in the SQL query below.
select member_id,
min(eff_dt) keep (dense_rank last order by diff nulls first) as eff_dt,
min(term_dt) keep (dense_rank last order by diff nulls first) as term_dt
from (
select member_id, eff_dt, term_dt,
eff_dt - lag(term_dt) over (partition by member_id order by eff_dt) as diff
from inputs
)
group by member_id
;
MEMBER_ID EFF_DT TERM_DT
--------- ------------------- -------------------
101 2015-01-01 00:00:00 2015-03-31 00:00:00

Oracle 11g - How to calculate the value of a number in range minimum or max

i need a help to get solution to my problem, Please.
I have a table like this :
ID Number
|6 |20.90 |
|7 |45.00 |
|8 |52.00 |
|9 |68.00 |
|10 |120.00 |
|11 |220.00 |
|12 |250.00 |
The first range is 0 - 20.90.
When the value is in the half, the value id is for the max range.
When i got value 20.91, i want to get "ID = 6".
If the value is 31.00, i want to get "ID = 6"
If the value is
33.95, i want to get "ID = 7".
if the value is 44.99, i want to get ID = 7
How i can do it? Is there a function that will do what I need?
If you want the record with a number that is closest to your input, then you can use this:
select *
from (
select *
from mytable
order by abs(number - my_input_number), id
)
where rownum < 2
The inner query selects all records, but orders them by the distance they have from your input number. This distance can be calculated with number - my_input_number. But that could be negative, so we take the absolute value of that. This result is not output; it is just used to order by. So records with smaller distances will come first.
Now we need just the first of those records, and that is what the outer query does with the typical Oracle reserved word rownum: it represents a sequence number for every record of the final result set (1, 2, 3, ...). The where clause will effectively filter away all records we do not want to see, leaving only one (with smallest distance).
As mathguy suggested in comments, the order by now also has a second value to order by in case the input value is right at the mid point between the two closest records. In that case the record with the lowest id value will be chosen.
This is a good illustration of the power of analytic functions:
with mytable ( id, value ) as (
select 6, 20.90 from dual union all
select 7, 45.00 from dual union all
select 8, 52.00 from dual union all
select 9, 68.00 from dual union all
select 10, 120.00 from dual union all
select 11, 220.00 from dual union all
select 12, 250.00 from dual
),
inputs ( x ) as (
select 0.00 from dual union all
select 20.91 from dual union all
select 31.00 from dual union all
select 33.95 from dual union all
select 44.99 from dual union all
select 68.00 from dual union all
select 32.95 from dual union all
select 400.11 from dual
)
-- End of test data (not part of the solution). SQL query begins BELOW THIS LINE
select val as x, new_id as closest_id
from (
select id, val,
last_value(id ignore nulls) over (order by val desc) as new_id
from (
select id, (value + lead(value) over (order by value))/2 as val
from mytable
union all
select null, x
from inputs
)
)
where id is null
order by x -- if needed
;
Output:
X CLOSEST_ID
------ ----------
0 6
20.91 6
31 6
32.95 6
33.95 7
44.99 7
68 9
400.11 12

How to breakdown data by month and showing zero for months with no data?

Using information in Table A, how can I produce results in Table B below?
Table A:
CASE_ID DATE_EFF COPAY STATUS
1 11/04/2016 10 A
1 11/20/2016 5 A
1 11/23/2016 5 R
1 12/01/2016 1 A
1 12/10/2016 2 A
1 12/12/2016 10 A
1 12/31/2016 50 R
For the above CASE_ID, we have dates in Nov 2016 and Dec 2016 only, however, I want to produce a breakdown of this CASE_ID for a period of 6 months as below where for each month the copays are summed where applicable as per the DATE_EFF and for the months that are not within the above dates, a zero is entered. Also, only records with copays with a status of 'A' are summed for any month -- so those with status of 'R' are ignored in the summation. For example, based on data in Table A above, the intended results are as follow:
Table B:
CASE_ID MONTH TOTAL_COPAY
1 01/2017 0
1 12/2016 13
1 11/2016 15
1 10/2016 0
1 09/2016 0
1 08/2016 0
I have below as a possible solution[using a with clause], but can this be achieved without the use of the 'with' clause?
Possible Solution:
WITH
XRF AS
( SELECT CASE_ID, COPAY, DATE_EFF
FROM Table_A WHERE STATUS = 'A'
)
SELECT F.CASE_ID, ST, NVL(SUM(F.COPAY),0) TOTAL_COPAY FROM XRF F PARTITION BY (F.CASE_ID)
RIGHT OUTER JOIN (SELECT '12/2016' ST FROM DUAL UNION ALL
SELECT '11/2016' FROM DUAL UNION ALL
SELECT '10/2016' FROM DUAL UNION ALL
SELECT '09/2016' FROM DUAL UNION ALL
SELECT '08/2016' FROM DUAL UNION ALL
SELECT '07/2016' FROM DUAL) STS
ON (TO_CHAR(LAST_DAY((F.DATE_EFF)),'MM/YYYY') = STS.ST)
GROUP BY F.CASE_ID, ST ORDER BY F.CASE_ID, ST DESC
;
UPDATE AND SOLUTION:
Using the above query, I believe I am have answered my own question by implementing it as below -- not sure though if using this method is expensive when you have millions of records of such CASE_IDs. Any thoughts?
SELECT F.CASE_ID, ST, NVL(SUM(F.COPAY),0) TOTAL_COPAY FROM (SELECT CASE_ID, COPAY, DATE_EFF FROM TABLE_A WHERE STATUS = 'A') F PARTITION BY (F.CASE_ID)
RIGHT OUTER JOIN (SELECT '12/2016' ST FROM DUAL UNION ALL
SELECT '11/2016' FROM DUAL UNION ALL
SELECT '10/2016' FROM DUAL UNION ALL
SELECT '09/2016' FROM DUAL UNION ALL
SELECT '08/2016' FROM DUAL UNION ALL
SELECT '07/2016' FROM DUAL) STS
ON (TO_CHAR(LAST_DAY((F.DATE_EFF)),'MM/YYYY') = STS.ST)
GROUP BY F.CASE_ID, ST ORDER BY F.CASE_ID, ST DESC
;

Oracle SQL Select Query Getting Max Row As a Fraction of a Rollup Total

hoping I might be able to get some advise regarding Oracle SQL…
I have a table roughly as follows (there are more columns, but not necessary for this example)…
LOCATION USER VALUE
1 1 10
1 2 20
1 3 30
2 4 10
2 5 10
2 6 20
1 60
2 40
100
I’ve used rollup to get subtotals.
What I need to do is get the max(value) row for each location and express the max(value) as a percentage or fraction of the subtotal for each location
ie:
LOCATION USER FRAC
1 3 0.5
2 6 0.5
I could probably solve this using my limited knowledge of select queries, but am guessing there must be a fairly quick and slick method..
Thanks in advance :)
Solution using analytic functions
(Please note the WITH MY_TABLE AS serving only as dummy datasource)
WITH MY_TABLE AS
( SELECT 1 AS LOC_ID,1 AS USER_ID, 10 AS VAL FROM DUAL
UNION
SELECT 1,2,20 FROM DUAL
UNION
SELECT 1,3,30 FROM DUAL
UNION
SELECT 2,4,10 FROM DUAL
UNION
SELECT 2,5,10 FROM DUAL
UNION
SELECT 2,6,20 FROM DUAL
)
SELECT LOC_ID,
USER_ID,
RATIO_IN_LOC
FROM
(SELECT LOC_ID,
USER_ID,
RATIO_IN_LOC,
RANK() OVER (PARTITION BY LOC_ID ORDER BY RATIO_IN_LOC DESC) AS ORDER_IN_LOC
FROM
(SELECT LOC_ID,
USER_ID,
VAL,
VAL/SUM(VAL) OVER (PARTITION BY LOC_ID) AS RATIO_IN_LOC
FROM MY_TABLE
)
)
WHERE ORDER_IN_LOC = 1
ORDER BY LOC_ID,
USER_ID;
Result
LOC_ID USER_ID RATIO_IN_LOC
1 3 0,5
2 6 0,5
with inputs ( location, person, value ) as (
select 1, 1, 10 from dual union all
select 1, 2, 20 from dual union all
select 1, 3, 30 from dual union all
select 2, 4, 10 from dual union all
select 2, 5, 10 from dual union all
select 2, 6, 20 from dual
),
prep ( location, person, value, m_value, total ) as (
select location, person, value,
max(value) over (partition by location),
sum(value) over (partition by location)
from inputs
)
select location, person, round(value/total, 2) as frac
from prep
where value = m_value;
Notes: Your table exists already? Then skip everything from "inputs" to the comma; your query should begin with with prep (...) as ( ...
I changed user to person since user is a keyword in Oracle, you shouldn't use it for table or column names (actually you can't unless you use double quotes, which is a very poor practice).
The query will output two or three or more rows per location if there are ties at the top. Presumably this is what you desire.
Output:
LOCATION PERSON FRAC
---------- ---------- ----------
1 3 .5
2 6 .5

Oracle sql retrive records based on maximum time

i have below data.
table A
id
1
2
3
table B
id name data1 data2 datetime
1 cash 12345.00 12/12/2012 11:10:12
1 quantity 222.12 14/12/2012 11:10:12
1 date 20/12/2012 12/12/2012 11:10:12
1 date 19/12/2012 13/12/2012 11:10:12
1 date 13/12/2012 14/12/2012 11:10:12
1 quantity 330.10 17/12/2012 11:10:12
I want to retrieve data in one row like below:
tableA.id tableB.cash tableB.date tableB.quantity
1 12345.00 13/12/2012 330.10
I want to retrieve based on max(datetime).
The data model appears to be insane-- it makes no sense to join an ORDER_ID to a CUSTOMER_ID. It makes no sense to store dates in a VARCHAR2 column. It makes no sense to have no relationship between a CUSTOMER and an ORDER. It makes no sense to have two rows in the ORDER table with the same ORDER_ID. ORDER is also a reserved word so you cannot use that as a table name. My best guess is that you want something like
select *
from customer c
join (select order_id,
rank() over (partition by order_id
order by to_date( order_time, 'YYYYMMDD HH24:MI:SS' ) desc ) rnk
from order) o on (c.customer_id=o.order_id)
where o.rnk = 1
If that is not what you want, please (as I asked a few times in the comments) post the expected output.
These are the results I get with my query and your sample data (fixing the name of the ORDER table so that it is actually valid)
SQL> ed
Wrote file afiedt.buf
1 with orders as (
2 select 1 order_id, 'iphone' order_name, '20121201 12:20:23' order_time from dual union all
3 select 1, 'iphone', '20121201 12:22:23' from dual union all
4 select 2, 'nokia', '20110101 13:20:20' from dual ),
5 customer as (
6 select 1 customer_id, 'paul' customer_name from dual union all
7 select 2, 'stuart' from dual union all
8 select 3, 'mike' from dual
9 )
10 select *
11 from customer c
12 join (select order_id,
13 rank() over (partition by order_id
14 order by to_date( order_time, 'YYYYMMDD HH24:MI:SS' ) desc ) rnk
15 from orders) o on (c.customer_id=o.order_id)
16* where o.rnk = 1
SQL> /
CUSTOMER_ID CUSTOM ORDER_ID RNK
----------- ------ ---------- ----------
1 paul 1 1
2 stuart 2 1
Try something like
SELECT *
FROM CUSTOMER c
INNER JOIN ORDER o
ON (o.CUSTOMER_ID = c.CUSTOMER_ID)
WHERE TO_DATE(o.ORDER_TIME, 'YYYYMMDD HH24:MI:SS') =
(SELECT MAX(TO_DATE(o.ORDER_TIME, 'YYYYMMDD HH24:MI:SS')) FROM ORDER)
Share and enjoy.

Resources