SQL & PL/SQL :: Using Rank Clause With Window Aggregate Functions
Jan 5, 2012
I am trying to use RANK() clause with a window clause...is that possible to use both together?
like
select col1, col2, col3,
RANK() OVER (ORDER BY col3 desc RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) RK
from table t
but getting error in SQL Developer
ORA-00907: missing right parenthesis
00907. 00000 - "missing right parenthesis"
*Cause:
*Action:
Error at Line: 2 Column: 33
The reason why i need to rank in window clause because i have data like this
Name Marks Quiz
Ali 10 1
John 20 1
Sara 30 1
John 40 2
Sara 50 2
Ali 20 2
...
...
and so on
I want to rank them based on their cumulative sum marks after every test..ranking should be in such a way that it should look current row and preceding rows
like this
Name Marks Quiz cumulative_marks rk
Ali 10 1 10 4
John 20 1 20 3
Sara 30 1 30 2
Peter 100 1 100 1
John 40 2 60 3 ==> becuase John has now third most overall cumulative marks (60) after quiz 2.
Sara 50 2 90 2 ==> becuase Sara has now 2nd most overall cumulative marks (90) after quiz 2.
Ali 20 2 30 4 ==> becuase Ali has now fouth most overall cumulative marks (30) after quiz 2.
i want to create a blood donor report, which consists of his profile, donations_n_tests details, donor_to_patient tracking. each is a different table which i have imported to the layout.
now the problem is that for the 1st ever layout that i make via the report builder wizard, it offers me to choose aggregate functions (like sum, cout, avg, etc). but for the rest of the tables that i import into this layout via ADDITIONAL LAYOUT OPTION (report block. it does not offer me these summary functions.
actually i can only configure aggrigate functions via the report layout wizard, perhaps report builder is not that friendly like form developer where we can put a display item set calculation mode to summary and specify the column for the aggregate function.
I have a function that returns the situation for one month for some database. I need to implement it in some report medium for one year. The one year function works ok.
My problem is when trying to make another function that runs the monthly function 12 times and that error is "PLS-00653: aggregate/table functions are not allowed in PL/SQL scope".am trying to get around some restrictions and somehow until this part things seem to be ok.
I tried to use a union with 12 blocks but it works very slow in the reporting environment and now i want to try to make another function that runs another function 12 times depending on the parameter.
here is the code (there might be some name misuse since i had to change the names of the original code -
CREATE OR REPLACE FUNCTION anual(monthh in varchar2, year IN VARCHAR2) return anual_REP_var PIPELINED is BR anual_REP:=anual_REP(NULL,NULL, NULL,NULL); contor INT(2);
In normal sql statement: select sum(order_items.quantity*items.price) sales_price from order_items,items where order.item_id=items.item_id;
I have to put this logic in either a stored procedure or Function just to calculate sum(order_items.quantity*items.price) and store the aggregated value as Sales_price in DB. Then we have to call this from Informatica Stored procedure Transformation where we will have only one output port as Sales_price,this is to load into summary table. All the aggregate calculations and joining of 2 tables should be done on DB side and only one output should be populated when we execute this procedure.
I certainly know this is possibly but I am trying to do this on the fly and can't seem to work it out:
I have a table A: ID Name Priority ------------------- 1 Smith 1 1 SSmith 2 1 ASmith 3 1 BSmith 3 2 John 2 3 Ed 1
and I am looking to create the following table from this: ID Name Sum(Top3Priority) -------------------------------- 1 Smith,SSmith,etc 8
Now, I've got listagg working and everything appears to be going swimmingly but: for every listagg grouping on name I need to only sum the highest top 3 priorities. So in the example above there are four Smiths but I need to only sum the top 3 priorities which are 3,3,2 and ignore the 1 even though I do want all the listagg Smith's (SSmiht, ASmith, etc) in there.
Now I can sum the priority, but don't really know how to sum only the top 3 in any ID ? There can be 1 to n ID's so if there are only 2 ID's I want to sum those 2, if there are 3 all 3 and 4 upwards only the top 3.Here is a snippet of the SQL I am using
SLECT id, listagg(MN_CR_LOOKUP.f_name, ',') within group (order by Priority)) roadname, **** sum top 3 here ?**** count(*) "NumI", Sum("Elevation") "CombinedElevation" FROM jc,
I am trying to find out the difference in time between peoples memberships and also the order that these memberships are taken out in. So far I have added in a rank statement to work out the order the memberships were created in, but now want to look at the difference between the dates returned. The SQL I used is:
SELECT owner_party_id, mem_number, support_id, mem_start_date, RANK() OVER (PARTITION BY owner_party_id ORDER BY mem_start_date ASC) MEMBERSHIP_SEQUENCE FROM membership_all WHERE version_type = 'CUR' AND owner_party_id IN ('65051', '65051', '65348', '65348', '65607', '65607', '65607')
I think that I need to use the Lag function in, but I am not too sure if it can be linked to look at the data within a grouping of owner party id, as it would make no sense to calculate the difference in dates for two different owner party ids.
I need to return which hour for a given date range had the most calls. I have a query that works but it is inelegant and I'm pretty sure I could do better. I'm pretty new to analytic queries so go easy...
select hour, calls from ( select hour, calls, rank() over (ORDER BY calls desc) as ranking from (
with tmp_tbl as (select 'H1' as hh_id, 'C1' as cust_id, 2 as f_rnk, 'F' as gender, to_date('20130102','YYYYMMDD') as purch_dt, to_date('20100203','YYYYMMDD') first_dt from dual union select 'H1' as hh_id, 'C2' as cust_id, 1 as f_rnk, 'M' as gender, to_date('20130102','YYYYMMDD') as purch_dt, to_date('20100303','YYYYMMDD') first_dt from dual union select 'H1' as hh_id, 'C3' as cust_id, cast(null as number) as f_rnk, 'U' as gender, to_date('20130103','YYYYMMDD') as purch_dt, [code].....
Now i need to rank each cust_id in each hh_id based on below conditions.
1) If atleaset one cust_id in hh_id has f_rnk then gender 'F' with highest f_rnk (more then one F with same f_rnk then the one with oldest first_dt), if no 'F' then gender 'U' with highest f_rnk ((more then one F with same f_rnk then the one with oldest first_dt)), if no 'F' and 'U' then consider 'M' (more then one M with same f_rnk then the one with oldest first_dt).
2) If the above is not met (no cust_id in hh_id has f_rnk populated) then i've to rank based on purch_dt. Gender 'F' with recent purch_dt (if more than one F in household with same purch_dt then the one with oldest first_dt), if no 'F' then gender 'U' with recent purch_dt (if more than one U in household with same purch_dt then one with oldest first_dt), if no 'F' and 'U' then consider 'M' (more than one M in household with same purch_dt then the one with oldest first_dt).
3) If the above criteria is also not met, then rank based on gender_cd. Gender 'F' will have first preference then 'U' and then 'M'.
My output :
HH_ID CUST_ID F_RNK GENDER PURCH_DT FIRST_DT F_RNK_RANK PURCH_RANK GENDER_ONLY_RANK ----- ------- ---------- ------ ----------- ----------- ------------ ------------ ----------------- H1 C1 2 F 1/2/2013 2/3/2010 1 H1 C2 1 M 1/2/2013 3/3/2010 2 H1 C3 U 1/3/2013 4/3/2010 3 H2 C4 F 4/3/2013 10/2/2009 2 H2 C5 M 5/5/2013 8/8/2010 1 H3 C6 F 5/6/2008 1 H3 C6 M 7/8/2010 2
I've tried below query with one condition, but it's giving f_rnk_rank for all records. How can i include multiple conditions in the rank function.
with tmp_tbl as (select 'H1' as hh_id, 'C1' as cust_id, 2 as f_rnk, 'F' as gender, to_date('20130102','YYYYMMDD') as purch_dt, to_date('20100203','YYYYMMDD') first_dt from dual union select 'H1' as hh_id, 'C2' as cust_id, 1 as f_rnk, 'M' as gender, to_date('20130102','YYYYMMDD') as purch_dt, to_date('20100303','YYYYMMDD') first_dt from dual union select 'H1' as hh_id, 'C3' as cust_id, cast(null as number) as f_rnk, 'U' as gender, to_date('20130103','YYYYMMDD') as purch_dt, s hh_id, 'C5' as cust_id, [code]....
there is a way when doing the Rank Function in PL/SQL to pass the field that will be ranked as an override.
SELECT rank(p_ColumnAmt) within group (order by p_ColumnNm desc) rank INTO v_RnkNoAmt FROM Table_name WHERE ??????;
p_Column is the amount I am ranking p_ColumnNm is the actual field name to Rank.
When I pass the field name with an override I do not get the correct rank back. If I run the Select with the actual field name curr_1_mth_amt, I get the correct rank.
I have about 70 different field to Rank and do not want to make a procedure for each field.
I have a SQL statement that return the following result.
col1 ---- a a b b a c c c c
What i need is to eliminate the duplication and return the result as the following.
col1 ---- a b a c
Using group by or distinct will eliminate the third row "a" and will not return it ordered.My idea is to generate another column that rank the result as following.
col1rank ------------ a1 a1 b2 b2 a3 c4 c4 c4 c4
so using the following SQL query will return the result as needed
select col1, rank from T group by col1, rank order by rank;
SELECT DISTINCT OUA_ID, TERM_COUNT, TERM FROM( SELECT OUA_ID, TERM ,PROVIDER_CDE, COUNT(*) TERM_COUNT FROM TABLE WHERE PROVIDER_CDE = 'BILL' GROUP BY OUA_ID, TERM, PROVIDER_CDE)) GROUP BY OUA_ID
Am working on a workbook to count the number of enrolments and withdrawals in the program. My data looks like this
name semester status year A 1 enrol 2010 A 2 withdraw 2010 A 3 enrol 2010 B 1 enrol 2010 B 2 withdraw 2010
I want to count their latest status only. It should come up with Total Enrol - 2 Total Withdrawn - 1
For total Withdrawn, I tried 'rank' and filter to equals 1 but it does not allow me. Is there any way to have this work? Here's my calculation:(decode((FIRST_VALUE(status) OVER(PARTITION BY year, name ORDER BY semester DESC)),'withdraw', name)) It tells me that 'Aggregation of Analytic function not allowed'
TFIDF_TABLE ID | TERMS 309 |'computer,phone,mp3....'
Now I want to add TERMS column of TERMS_TABLE to terms column of TFIDF_TABLE but If TFIDF_TABLE already contains TERMS of TERMS_TABLE then I should not insert this term to the NEW_TFIDF_TABLE , like that
result should be:
NEW_TFIDF_TABLE ID | TERMS 309 |'computer,phone,mp3....,hardware,software'
SELECT field1, COUNT(x) AS COUNT FROM my_table GROUP BY field1;
For field1 I want to get a count, but if field1 is like 'ABC%' then I want to combine all of those.
So if I have the following: ABC1 | 5 ABC2 | 10 XYZ1 | 3
I want results like this: ABC | 15 XYZ1 | 3
I've tried using some case statements like
SELECT CASE WHEN field1 LIKE 'ABC%' THEN 'ABC' ELSE field1 END AS field1, COUNT(x) AS COUNT FROM my_table GROUP BY CASE WHEN field1 LIKE 'ABC%' THEN 'ABC' ELSE field1 END;
but this just gives me ABC | 5 ABC | 10 XYZ1 | 3
How can I combine record 1 and 2 from the last record set example above?
The value is an aggregate Year to Date Figure And I was wondering what the best method of splitting this data out into a Monthly Figure so that it would look like below:
Year Month Mth Value 2011 01 15 2011 02 11 2011 03 8 2011 04 9
I intend to get for every client the start date and end of a contiguous range of days. Example for the same client have two records, in the first goes from day 1 to day 5 and the second from day 3 to day 9, i intend to get a record for this client where indicated that the start date is on day 1 and ending on Day 9.
SELECT 123 as CLI_ID, TO_DATE('20100101', 'YYYYMMDD') as DT_START, TO_DATE('20100105', 'YYYYMMDD') as DT_END FROM DUAL UNION SELECT 123 as CLI_ID, TO_DATE('20100208', 'YYYYMMDD') as DT_START, TO_DATE('20100321', 'YYYYMMDD') as DT_END FROM DUAL UNION SELECT 123 as CLI_ID, TO_DATE('20100219', 'YYYYMMDD') as DT_START, TO_DATE('20100228', 'YYYYMMDD') as DT_END FROM DUAL UNION SELECT 123 as CLI_ID, TO_DATE('20100227', 'YYYYMMDD') as DT_START, TO_DATE('20100405', 'YYYYMMDD') as DT_END FROM DUAL UNION SELECT 123 as CLI_ID, TO_DATE('20100901', 'YYYYMMDD') as DT_START, TO_DATE('20101013', 'YYYYMMDD') as DT_END FROM DUAL
I can' use sequence in the group by function and if I get equivalent analytic for above group by even then I can't write row_number as the order by gives detail record
I don't want to wrap this select inside other select