SQL report - Matching percent value with a number - sql

I have a small issue with my report and I need to know if its even possible to do it?
Im using Oracle12c and the tool OBIEE, im trying to create a custom column with numbers values (1 and 2) that are matching my results from my "Percent" column in a way I described below.
Here is my results in table:
I will give u an example of how it should work:
Emilian is an owner of few customers, the customers have their annual revenue listed and the column next to it its the Percent value of the total customer revenue for Emilian. Now, in my custom column I need to show "1" for customers that contribute more than (or exact) 80% of his total and "2" for the rest. So in Emilian Case, his first two customers will be "1" since 78% + 14% is already above 80% and the rest will be "2". For other Owners that only have one customer, all of them logically would be matched with "1" since their contribution is 100%
Hope I made this clear, will be veery grateful for the help with coding it :)
Alex

There's probably a much more efficient way to do this. I built up what you need to get at with a series of sub-selects. This still doesn't handle the equal percents, but you said that isn't an expected problem. I'd still watch out for it.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE t1 ( ownerId int, customerId int, revenue int ) ;
INSERT INTO t1 ( ownerid, customerid, revenue )
SELECT 1, 1, 99 FROM dual UNION ALL
SELECT 1, 2, 200 FROM dual UNION ALL
SELECT 1, 3, 300 FROM dual UNION ALL
SELECT 1, 4, 400 FROM dual UNION ALL
SELECT 2, 5, 100 FROM dual UNION ALL
SELECT 2, 6, 100 FROM dual UNION ALL
SELECT 2, 7, 200 FROM dual UNION ALL
SELECT 2, 8, 600 FROM dual UNION ALL
SELECT 3, 9, 100 FROM dual UNION ALL
SELECT 3, 10, 900 FROM dual UNION ALL
SELECT 4, 11, 1000 FROM dual UNION ALL
SELECT 5, 12, 1000 FROM dual UNION ALL
SELECT 6, 13, 200 FROM dual UNION ALL
SELECT 6, 14, 200 FROM dual UNION ALL
SELECT 6, 15, 200 FROM dual UNION ALL
SELECT 6, 16, 200 FROM dual UNION ALL
SELECT 6, 17, 200 FROM dual UNION ALL
SELECT 42, 736784, 1480000 FROM dual UNION ALL
SELECT 42, 736580, 280160 FROM dual UNION ALL
SELECT 42, 1040137, 112486 FROM dual UNION ALL
SELECT 42, 738685, 22903 FROM dual UNION ALL
SELECT 42, 736781, 56 FROM dual
;
Query 1:
SELECT s3.ownerID, s3.customerID, s3.revenue, s3.OwnerRevenue
, CAST(s3.customerRevPct AS decimal(5,2)) AS customerRevPct
, CASE WHEN s3.PctRT < 80 OR s3.custCount = 1 THEN 1 ELSE 2 END AS customCol
/* Do the running pcts add up to 80+? 1 customer = 100% == 1. What if all are pcts are equal? */
FROM (
SELECT s2.*
, 100-SUM(nvl(s2.customerRevPct,0)) OVER (PARTITION BY s2.ownerID ORDER BY s2.customerRevPct, s2.customerID RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS pctRT
, COUNT(*) OVER (PARTITION BY s2.ownerID ORDER BY (s2.ownerID) ) AS custCount /* Is there only 1 customer? */
FROM (
SELECT s1.*
, ( ( ( s1.revenue * 1.0 ) / s1.ownerRevenue ) * 100 ) AS customerRevPct
FROM (
SELECT t1.ownerID, t1.customerID, t1.revenue
, SUM(t1.revenue) OVER ( PARTITION BY t1.ownerID ) AS ownerRevenue
FROM t1
) s1
) s2
) s3
WHERE ownerID = 42 /* REMOVE THIS LINE - TESTING ONLY */
ORDER BY s3.ownerID, s3.customerRevPct DESC
Results:
| OWNERID | CUSTOMERID | REVENUE | OWNERREVENUE | CUSTOMERREVPCT | CUSTOMCOL |
|---------|------------|---------|--------------|----------------|-----------|
| 42 | 736784 | 1480000 | 1895605 | 78.08 | 1 |
| 42 | 736580 | 280160 | 1895605 | 14.78 | 1 |
| 42 | 1040137 | 112486 | 1895605 | 5.93 | 2 |
| 42 | 738685 | 22903 | 1895605 | 1.21 | 2 |
| 42 | 736781 | 56 | 1895605 | 0 | 2 |
EDIT: I changed the Fiddle to illustrate your data example.

create table custrev(owner varchar2(100), cust_id number, revenue number);
insert into custrev values('Emilian',1,1480000);
insert into custrev values('Emilian',2,280160);
insert into custrev values('Emilian',3,112486);
insert into custrev values('Emilian',4,22903);
insert into custrev values('Emilian',5,56);
insert into custrev values('Andy',6,1378);
insert into custrev values('Sandy',7,560000);
commit;
Below is the SQL for your requirement.
select owner, cust_id, revenue, pct,
case when pct = 100 then 1
when flg is null or flg < 80 then 1
else 2 end flag_col
from (select owner, cust_id, revenue, pct,--cumulative_sum,
lag(cumulative_sum) over(partition by owner
order by revenue desc) flg
from (select owner, cust_id, revenue, pct,
sum(pct) over(partition by owner
order by revenue desc
rows between unbounded preceding
and current row) cumulative_sum
from (select owner, cust_id, revenue,
round(ratio_to_report(revenue) over(partition by owner)*100,2) pct
from custrev)
)
)
order by owner, revenue desc;
Output:
OWNER CUST_ID REVENUE PCT FLAG_COL
Andy 6 1378 100 1
Emilian 1 1480000 78.08 1
Emilian 2 280160 14.78 1
Emilian 3 112486 5.93 2
Emilian 4 22903 1.21 2
Emilian 5 56 0 2
Sandy 7 560000 100 1

Alex,
OBIEE is based on models. Not on SQL.
So sorry to say this but the SQL code will help you exactly zero...

Related

Select rows when a value appears multiple times

I have a table like this one:
+------+------+
| ID | Cust |
+------+------+
| 1 | A |
| 1 | A |
| 1 | B |
| 1 | B |
| 2 | A |
| 2 | A |
| 2 | A |
| 2 | B |
| 3 | A |
| 3 | B |
| 3 | B |
+------+------+
I would like to get the IDs that have at least two times A and two times B. So in my example, the query should return only the ID 1,
Thanks!
In MySQL:
SELECT id
FROM test
GROUP BY id
HAVING GROUP_CONCAT(cust ORDER BY cust SEPARATOR '') LIKE '%aa%bb%'
In Oracle
WITH cte AS ( SELECT id, LISTAGG(cust, '') WITHIN GROUP (ORDER BY cust) custs
FROM test
GROUP BY id )
SELECT id
FROM cte
WHERE custs LIKE '%aa%bb%'
I would just use two levels of aggregation:
select id
from (select id, cust, count(*) as cnt
from t
where cust in ('A', 'B')
group by id, cust
) ic
group by id
having count(*) = 2 and -- both customers are in the result set
min(cnt) >= 2 -- and there are at least two instances
This is one option; lines #1 - 13 represent sample data. Query you might be interested in begins at line #14.
SQL> with test (id, cust) as
2 (select 1, 'a' from dual union all
3 select 1, 'a' from dual union all
4 select 1, 'b' from dual union all
5 select 1, 'b' from dual union all
6 select 2, 'a' from dual union all
7 select 2, 'a' from dual union all
8 select 2, 'a' from dual union all
9 select 2, 'b' from dual union all
10 select 3, 'a' from dual union all
11 select 3, 'b' from dual union all
12 select 3, 'b' from dual
13 )
14 select id
15 from (select
16 id,
17 sum(case when cust = 'a' then 1 else 0 end) suma,
18 sum(case when cust = 'b' then 1 else 0 end) sumb
19 from test
20 group by id
21 )
22 where suma = 2
23 and sumb = 2;
ID
----------
1
SQL>
You can use group by and having for the relevant Cust ('A' , 'B')
And query twice (I chose to use with to avoid multiple selects and to cache it)
with more_than_2 as
(
select Id, Cust, count(*) c
from tab
where Cust in ('A', 'B')
group by Id, Cust
having count(*) >= 2
)
select *
from tab
where exists ( select 1 from more_than_2 where more_than_2.Id = tab.Id and more_than_2.Cust = 'A')
and exists ( select 1 from more_than_2 where more_than_2.Id = tab.Id and more_than_2.Cust = 'B')
What you want is a perfect candidate for match_recognize. Here you go:
select id_ as id from t
match_recognize
(
order by id, cust
measures id as id_
pattern (A {2, } B {2, })
define A as cust = 'A',
B as cust = 'B'
)
Output:
Regards,
Ranagal

SQL: summing a column starting from row immediately after two consecutive 'trigger' values in another column

How to sum all values after two consecutive YES's in the CONDITION_SATISFIED column?
ID | CONDITION_SATISFIED | VALUE
--------------------------------
1 | NO | 100
2 | NO | 300
3 | NO | 500
4 | YES | 100
5 | YES | 300
6 | NO | 500 <-
7 | NO | 100 <-
8 | YES | 300 <-
9 | NO | 500 <-
--------------------------------
SUM | 1400
Note: further occurrences of YES/NO are ignored once the summation is started.
I've gotten to the point where I am able to generate two extra columns for the CONDITION_SATISFIED column like this:
ID | CONDITION_SATISFIED | VALUE RANK | REPEAT_COUNT
-------------------------------- -------------------
1 | NO | 100 1 | 3
2 | NO | 300 1 | 3
3 | NO | 500 1 | 3
4 | YES | 100 2 | 2
5 | YES | 300 2 | 2
6 | NO | 500 3 | 2 <- start from here
7 | NO | 100 3 | 2
8 | YES | 300 4 | 1
9 | NO | 500 5 | 1
-------------------------------- -------------------
But I'm not able to figure out how to get the first instance of REPEAT_COUNT >= 2 AND CONDITION_SATISFIED = 'YES', and then start the summation immediately after the 2nd YES (as indicated).
Hmmm . . . You can get the first where the two yesses are using lag():
select t.*
from (select t.*,
lag(condition_satisfied) over (order by id) as prev_cs,
lag(condition_satisfied, 2) over (order by id) as prev2_cs
from t
) t
where prev2_cs = 'YES' and prev_cs = 'YES';
Then you can just use this in a query:
select t.*
from t join
(select min(t.id) as id
from (select t.*,
lag(condition_satisfied) over (order by id) as prev_cs,
lag(condition_satisfied, 2) over (order by id) as prev2_cs
from t
) t
where prev2_cs = 'YES' and prev_cs = 'YES'
) yy
on t.id >= yy.id;
Oracle 12c: pattern matching
with t1 (id, condition_satisfied, value) as (
select 1, 'NO' , 100 from dual union all
select 2, 'NO' , 300 from dual union all
select 3, 'NO' , 500 from dual union all
select 4, 'YES', 100 from dual union all
select 5, 'YES', 300 from dual union all
select 6, 'NO' , 500 from dual union all
select 7, 'NO' , 100 from dual union all
select 8, 'YES', 300 from dual union all
select 9, 'NO' , 500 from dual)
select sum(v_value) as sum_value
from t1
match_recognize(
order by id
measures s.value as v_value
all rows per match
pattern (yes{2} s+)
define
yes as condition_satisfied = 'YES'
);
SUM_VALUE
----------
1400
If you have version lower than 12 no need to self-join and generate/prevent duplicates:
with s (id, condition_satisfied, value) as (
select 1, 'NO' , 100 from dual union all
select 2, 'NO' , 300 from dual union all
select 3, 'NO' , 500 from dual union all
select 4, 'YES', 100 from dual union all
select 5, 'YES', 300 from dual union all
select 6, 'NO' , 500 from dual union all
select 7, 'YES' , 100 from dual union all
select 8, 'YES', 300 from dual union all
select 9, 'NO' , 500 from dual)
select sum(value) sum_value
from
(select s.*, min(first_id) over () min_id
from
(select s.*,
case when condition_satisfied = 'YES' and condition_satisfied = lag(condition_satisfied) over (order by id) then id end first_id
from s
) s
)
where id > min_id;
SUM_VALUE
----------
1400

How can I use the self join to find equal values within a group?

I am looking to find instances of GROUPID where all price values are 0. The following is a simplified version of what I am looking at
--------------------------------
| Groupid | Price | Customer|
--------------------------------
| 001 | 9 | 4 |
| 001 | 0 | 4 |
| 002 | 4 | 4 |
| 002 | 4 | 4 |
| 003 | 0 | 4 |
| 003 | 0 | 4 |
| 004 | 4 | 4 |
| 004 | 7 | 4 |
--------------------------------
I am attempting to use the following query to find all GROUPID where both PRICE values for that particular group = 0.
SELECT * FROM MYTABLE WHERE GROUPID IN
(SELECT TB1.GROUPID FROM MYTABLE TB1 JOIN MYTABLE TB2 ON TB1.GROUPID = TB2.GROUPID
AND TB1.PRICE = 0 AND TB2.PRICE = 0)
and CUSTOMER = 4
ORDER BY GROUPID;
This query returns:
| Groupid | Price | Customer|
--------------------------------
| 001 | 9 | 4 |
| 001 | 0 | 4 |
| 003 | 0 | 4 |
| 003 | 0 | 4 |
--------------------------------
In my case, I only need it to return GROUPID 003.
I'd also like to ask for assistance in modifying the query to return all non 0 equal PRICE values within a groupid. It doesn't have to be in the same query as above. For example the return would be:
| Groupid | Price | Customer|
--------------------------------
| 002 | 4 | 4 |
| 002 | 4 | 4 |
Any help would be appreciated. Thank you for your time.
If all the prices are zero, then look at the minimum and maximum price for the groupid:
select groupid
from mytable t
group by groupid
having min(price) = 0 and max(price) = 0;
I should point out that no self-join is required for this.
Try this:
SELECT * FROM MYTABLE as m1 where Price = 0
and not exists (
select 1
from MYTABLE as m2
where m2.Groupid = m1.Groupid
and m2.Price <> 0
)
You can list the the rows, whose group_id has no rows with non-zero price
select groupid, price, customer from mytable t
where not exists (
select 1 from mytable where group_id = t.group_id
and price != 0
);
I would do it by counting the number of distinct prices over each group (and I'm assuming that each group will have the same customer) and then filtering on the price(s) you're interested in.
For example, for prices that are 0 for all rows in each groupid+customer:
WITH mytable AS (SELECT '001' groupid, 9 price, 4 customer FROM dual UNION ALL
SELECT '001' groupid, 0 price, 4 customer FROM dual UNION ALL
SELECT '002' groupid, 4 price, 4 customer FROM dual UNION ALL
SELECT '002' groupid, 4 price, 4 customer FROM dual UNION ALL
SELECT '003' groupid, 0 price, 4 customer FROM dual UNION ALL
SELECT '003' groupid, 0 price, 4 customer FROM dual UNION ALL
SELECT '004' groupid, 4 price, 4 customer FROM dual UNION ALL
SELECT '004' groupid, 7 price, 4 customer FROM dual)
SELECT groupid,
customer,
price
FROM (SELECT groupid,
customer,
price,
COUNT(DISTINCT price) OVER (PARTITION BY groupid, customer) num_distinct_prices
FROM mytable)
WHERE num_distinct_prices = 1
AND price = 0;
GROUPID CUSTOMER PRICE
------- ---------- ----------
003 4 0
003 4 0
Just change the and price = 0 to and price != 0 if you want the groups which have the same non-zero price for all rows. Or simply remove that predicate altogether.
EDIT
Gordon's is the best solution for the first part:
SELECT groupid
FROM mytable t
GROUP BY GroupID
HAVING (MAX(price) = 0 and MIN(price) = 0)
And for the second part:
SELECT groupid
FROM mytable t
GROUP BY GroupID
HAVING MIN(price) <> 0 AND (MAX(price) = MIN(price))
My original one:
SELECT groupid
FROM mytable t
GROUP BY GroupID
HAVING SUM(Price) =0
This assumes, there are no negative prices.
To the second part of your question:
SELECT groupid
FROM mytable t
WHERE Price > 0
GROUP BY GroupID, Price
HAVING COUNT(price) > 1
In your sample data, you have only one customer. I assume if you had more than one customer, you would still want to return the rows where the groupid has the same price, across all rows and all customers. If so, you could use the query below. It is almost the same as Boneist's - I just use min(price) and max(price) instead of count(distinct), and I don't include customer in partition by.
If the price may be NULL, it will be ignored in the computation of max price and min price; if all the NON-NULL prices are equal for a groupid, all the rows for that group will be returned. If price can be NULL and this is NOT the desired behavior, that can be changed easily - but the OP will have to clarify.
The query below retrieves all the cases when there is a single price for the groupid. To retrieve only the groups where the price is 0 (an additional condition), add and price = 0 to the WHERE clause of the outer query. I added more test data to illustrate some of the cases the query covers.
with
test_data ( groupid, price, customer ) as (
select '001', 9, 4 from dual union all
select '001', 0, 4 from dual union all
select '002', 4, 4 from dual union all
select '002', 4, 4 from dual union all
select '003', 0, 4 from dual union all
select '003', 0, 4 from dual union all
select '004', 4, 4 from dual union all
select '004', 7, 4 from dual union all
select '002', 4, 8 from dual union all
select '005', 2, 8 from dual union all
select '005', null, 8 from dual
),
prep ( groupid, price, customer, min_price, max_price) as (
select groupid, price, customer,
min(price) over (partition by groupid),
max(price) over (partition by groupid)
from test_data
)
select groupid, price, customer
from prep
where min_price = max_price
;
GROUPID PRICE CUSTOMER
------- --------- ---------
002 4 8
002 4 4
002 4 4
003 0 4
003 0 4
005 8
005 2 8
This may be what you want:
SELECT * FROM MYTABLE
WHERE GROUPID NOT IN (
SELECT GROUPID
FROM MYTABLE
WHERE Price <> 0)
and just change the last line for the other query:
SELECT * FROM MYTABLE
WHERE GROUPID NOT IN (
SELECT GROUPID
FROM MYTABLE
WHERE Price = 0)
I would do it very similarly to what Gordon posted
SELECT groupId
FROM MyTable
GROUP BY groupId
HAVING SUM(price) = 0

Selecting groups of rows where at least one row of each group meets a criteria

I'm trying to SELECT groups of rows having one row with a certain criteria.
I've tried it with CASE WHEN statements without any success. Keep in mind this table has hundred of records.
What I'm trying to accomplish is this:
One row of the group must have a subcategory equal to "GAMECONSOLE".
Rows having the same category, description and section form one group.
The ID is different so MIN and MAX does not work either.
ID SECTION DESCRIPTION CATEGORY SUBCATEGORY
21349 14010014 TODDLER TOY GAMECONSOLE
21278 14010014 TODDLER TOY BICYCLE
21431 15020021 TODDLER TOY CHESS
In this example the two first rows should be selected because they form one group and one row of the group is a "GAMECONSOLE".
CASE WHEN is used when you have to take a decision within a column expression. Filtering on row level must be done in a WHERE clause:
SELECT T.id, T.section, T.description, T.category, T.subcategory
FROM
myTable T
INNER JOIN myTable S
ON T.section = S.section AND
T.description = S.description AND
T.category = S.category
WHERE
S.subcategory = 'GAMECONSOLE'
You can join the table with itself on the columns that have to be equal. The table with alias S selects the right subategory. T selects all corresponding rows of the groups.
SELECT a1.ID
, a1.SECTION
, a1.DESCRIPTION
, a1.CATEGORY
, a1.SUBCATEGORY
FROM MyTable a1
INNER JOIN MyTable a2 ON a2.DESCRIPTION = a1.DESCRIPTION
AND a2.CATEGORY = a1.CATEGORY
AND a2.SECTION = a1.SECTION
WHERE a2.SUBCATEGORY = 'GAMECONSOLE'
-- you may want to further filter the Where clause and apply a group by or distinct to get the actual results you are wanting
Your description sounds like:
select
...
from
(
select
...
,sum(case when subcategory = 'GAMECONSOLE' then 1 else 0 end)
over (partition by category, description, section) as cnt
from tab
) dt
where cnt > 0
SELECT *
FROM myTable T
WHERE Section = (SELECT Section
FROM myTable Q
WHERE Q.subcategory = 'GAMECONSOLE')
Using an analytic function you can get the answer without using a self join.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TEST( ID, SECTION, DESCRIPTION, CATEGORY, SUBCATEGORY ) AS
SELECT 1, 1, 'TODDLER', 'TOY', 'GAMECONSOLE' FROM DUAL
UNION ALL SELECT 2, 1, 'TODDLER', 'TOY', 'BICYCLE' FROM DUAL
UNION ALL SELECT 3, 2, 'TODDLER', 'TOY', 'CHESS' FROM DUAL
UNION ALL SELECT 4, 3, 'COMPUTERS', 'SOFTWARE', 'BOOK' FROM DUAL
UNION ALL SELECT 5, 4, 'COMPUTERS', 'SOFTWARE', 'SOFTWARE' FROM DUAL
UNION ALL SELECT 6, 5, 'COMPUTERS', 'HARDWARE', 'MONITOR' FROM DUAL
UNION ALL SELECT 7, 6, 'COMPUTERS', 'HARDWARE', 'GAMECONSOLE' FROM DUAL
UNION ALL SELECT 8, 7, 'COMPUTERS', 'HARDWARE', 'KEYBOARD' FROM DUAL
UNION ALL SELECT 9, 8, 'TODDLER', 'BEDDING', 'BED' FROM DUAL
Query 1:
SELECT ID, SECTION, DESCRIPTION, CATEGORY, SUBCATEGORY
FROM (
SELECT t.*,
COUNT( CASE SUBCATEGORY WHEN 'GAMECONSOLE' THEN 1 END ) OVER ( PARTITION BY DESCRIPTION, CATEGORY ) AS HAS_SUBCATEGORY
FROM TEST t
)
WHERE HAS_SUBCATEGORY > 0
Results:
| ID | SECTION | DESCRIPTION | CATEGORY | SUBCATEGORY |
|----|---------|-------------|----------|-------------|
| 8 | 7 | COMPUTERS | HARDWARE | KEYBOARD |
| 7 | 6 | COMPUTERS | HARDWARE | GAMECONSOLE |
| 6 | 5 | COMPUTERS | HARDWARE | MONITOR |
| 3 | 2 | TODDLER | TOY | CHESS |
| 2 | 1 | TODDLER | TOY | BICYCLE |
| 1 | 1 | TODDLER | TOY | GAMECONSOLE |
Try
SELECT * FROM <TABLE_NAME> WHERE SUBCATEGORY like "GAMECONSOLE";
or
SELECT * FROM <TABLE_NAME> WHERE SUBCATEGORY = "GAMECONSOLE";
Replace <TABLE_NAME> with the actual table name.
Further readings:
https://dev.mysql.com/doc/refman/5.0/en/select.html

Sorting by max value [duplicate]

This question already has answers here:
How to select records with maximum values in two columns?
(2 answers)
Closed 9 years ago.
I have a table that looks like this in an Oracle DB:
TransactionID Customer_id Sequence Activity
---------- ------------- ---------- -----------
1 85 1 Forms
2 51 2 Factory
3 51 1 Forms
4 51 3 Listing
5 321 1 Forms
6 321 2 Forms
7 28 1 Text
8 74 1 Escalate
And I want to be able to sort out all rows where sequence is the highest for each customer_id.
I there a MAX() function I could use on sequence but based on customer_id somehow?
I would like the result of the query to look like this:
TransactionID Customer_id Sequence Activity
---------- ------------- ---------- -----------
1 85 1 Forms
4 51 3 Listing
6 321 2 Forms
7 28 1 Text
8 74 1 Escalate
select t1.*
from your_table t1
inner join
(
select customer_id, max(Sequence) mseq
from your_table
group by customer_id
) t2 on t1.customer_id = t2.customer_id and t1.sequence = t2.mseq
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE tbl ( TransactionID, Customer_id, Sequence, Activity ) AS
SELECT 1, 85, 1, 'Forms' FROM DUAL
UNION ALL SELECT 2, 51, 2, 'Factory' FROM DUAL
UNION ALL SELECT 3, 51, 1, 'Forms' FROM DUAL
UNION ALL SELECT 4, 51, 3, 'Listing' FROM DUAL
UNION ALL SELECT 5, 321, 1, 'Forms' FROM DUAL
UNION ALL SELECT 6, 321, 2, 'Forms' FROM DUAL
UNION ALL SELECT 7, 28, 1, 'Text' FROM DUAL
UNION ALL SELECT 8, 74, 1, 'Escalate' FROM DUAL;
Query 1:
SELECT
MAX( TransactionID ) KEEP ( DENSE_RANK LAST ORDER BY Sequence ) AS TransactionID,
Customer_ID,
MAX( Sequence ) KEEP ( DENSE_RANK LAST ORDER BY Sequence ) AS Sequence,
MAX( Activity ) KEEP ( DENSE_RANK LAST ORDER BY Sequence ) AS Activity
FROM tbl
GROUP BY Customer_ID
ORDER BY TransactionID
Results:
| TRANSACTIONID | CUSTOMER_ID | SEQUENCE | ACTIVITY |
|---------------|-------------|----------|----------|
| 1 | 85 | 1 | Forms |
| 4 | 51 | 3 | Listing |
| 6 | 321 | 2 | Forms |
| 7 | 28 | 1 | Text |
| 8 | 74 | 1 | Escalate |
Please Try it
with cte as
(
select Customer_id,MAX(Sequence) as p from Tablename group by Customer_id
)
select b.* from cte a join Tablename b on a.p = b.Sequence where a.p = b.Sequence and a.Customer_id=b.Customer_id order by b.TransactionID