HTMLDB 1.6 and "order by" in analytic functions
In HTMLDB 1.6, oracle 10g, when i enter the string "order by" in the region source of a report of the type "sql query (pl/sql function body returning sql query", I get
1 error has occurred
* Your query can't include an "ORDER BY" clause when having column heading sorting enabled.
I understand the reason for this error, but unfortunately i need this for an analytic function:
row_number() over (partition by ... order by ...)
It seems that the check is performed by simply looking for the string "order by" in the "region source" (in fact the error fires even if that string is contained within a comment).
I know possible workarounds (eg creating a view and select'ing from it), i just wanted to let you know.
Regards
Alberto
Another one under the 'obvious route' category:
Seems that the ORDER BY check is apparentl for ORDER<space>BY... so simply adding extra whitespace between ORDER and BY bypasses the check (at least in 2.1.0.00.39).
To make it a bit more obious that a separation is intended, an empty comment, i.e. ORDER/*/BY*, works nicely
Edited by: mcstock on Nov 19, 2008 10:29 AM
Similar Messages
-
Order by in analytic functions
Hi All,
Please explain on how the order by clause in an analytic function vary the results ?.For eg.I get different results for SALSUM column if I order the below query by deptno/empno.
SELECT empno en,deptno dn,sal sal,SUM(sal) OVER (partition by deptno ORDER BY deptno) salsum FROM emp;
EN DN SAL SALSUM
10 1 100 525
20 1 200 525
50 1 225 525
60 2 125 275
30 2 150 275
40 3 250 250
SELECT empno en,deptno dn,sal sal,SUM(sal) OVER (partition by deptno ORDER BY empno) salsum
FROM emp;
EN DN SAL SALSUM
10 1 100 100
20 1 200 300
50 1 225 525
30 2 150 150
60 2 125 275
40 3 250 250Hi,
SUM(sal) OVER (partition by deptno ORDER BY deptno)
In the above example. you compute sum(sal) department wise in the ascending order of the employee id
then the sum of amt dept 1 will be 525 (since it will sum up amounts acorrding to ascending order of dept no. which must be 1 since the data is partitioned by dept no. hence amt is same accross all the records i.e. 525 accross dept no 1)
and for dept 2 = 275
SUM(sal) OVER (partition by deptno ORDER BY empno)
for the second scenario ..
it will sum up the amounts partitioning by dept no. but considering the order of employee id in ascending order.
e.g for dept 1 there are 3 employess 10,20,50 arranged in ascending order
so the sumsal for emp no 10 = 100
for 10 & 20 = 100+200 = 300
& for 10 ,20, 50 = 100+200+225 = 525
Hope this calrifies.. -
Goods Supplier (GS) and Ordering Address (OA) Partner functions
Hello!
Is it true that vendors that play the role of OA and GS partners do not need a purchasing view?
That is what I am noticing... but before I tell the users that they don't need to create purchasing views for vendors that are purely used as OA or GS, I wanted to reconfirm this with some experts, in case I am missing something in my tests.
Thanks,
Anisha.Hi Anisha,
Purchasing View must be maintained for your vendor master record because it contain all the key information related.
Such as if you want to activate Gr Based invoice verification for your vendor .Also it Auto Purchase creation is possible if the the radio button is ticked in purchasing view of it and material master record.
I think purchasing view must be maintained for the vendor master record.
Regards,
Tushar Patankar -
How to use analytic function with aggregate function
hello
can we use analytic function and aggrgate function in same qurey? i tried to find any example on Net but not get any example how both of these function works together. Any link or example plz share with me
Edited by: Oracle Studnet on Nov 15, 2009 10:29 PMselect
t1.region_name,
t2.division_name,
t3.month,
t3.amount mthly_sales,
max(t3.amount) over (partition by t1.region_name, t2.division_name)
max_mthly_sales
from
region t1,
division t2,
sales t3
where
t1.region_id=t3.region_id
and
t2.division_id=t3.division_id
and
t3.year=2004
Source:http://www.orafusion.com/art_anlytc.htm
Here max (aggregate) and over partition by (analytic) function is in same query. So it means we can use aggregate and analytic function in same query and more than one analytic function in same query also.
Hth
Girish Sharma -
I need to categorize the entries in col c1 as follows:
1. if the entry in col c1 has only positive values in col c2, then that entry in col c1 gets a category of PRD.
2. if the entry in col c1 has only negative values in col c2, then that entry in col c1 gets a category of RMT.
3. if the entry in col c1 has both positive and negative values in col c2, then that entry in col c1 gets a category of INT.
Here's the data table:
CREATE TABLE K_TST
C1 VARCHAR2(10),
C2 NUMBER
c1 c2
a 1
a -1
a -3
a 2
a -2
b 1
c -1
d 1
d 2
d 3
So I use the following query:
select a.c1,
a.init_category,
count(*) over (partition by a.c1) category_count,
decode(count(*) over (partition by a.c1), 1, a.init_category, 'INT') final_category
from
select distinct
c1,
decode(instr(to_char(c2), '-'), 0, 'PRD', 'RMT') init_category
from k_tst
) a
The idea is that I assign only categories PRD and RMT in the sub-query and then use the analytical function to count if an entry in col c1 belongs to more than one category. If it belongs to more than one category in the subquery, then the category is reassigned to INT.
No problem, the result is:
C1 INIT_CATEGORY CATEGORY_COUNT FINAL_CATEGORY
a PRD 2 INT
a RMT 2 INT
b PRD 1 PRD
c RMT 1 RMT
d PRD 1 PRD
The report that I want is without INIT_CATEGORY col and only distinct values, so I modify the query from above to this:
select distinct
a.c1,
-- a.init_category,
count(*) over (partition by a.c1) category_count,
decode(count(*) over (partition by a.c1), 1, a.init_category, 'INT') final_category
from
select distinct
c1,
decode(instr(to_char(c2), '-'), 0, 'PRD', 'RMT') init_category
from k_tst
) a
The result is:
C1 CATEGORY_COUNT FINAL_CATEGORY
a 5 INT
b 1 PRD
c 1 RMT
d 3 INT
Note the the CATEGORY_COUNT for 'a' changed to 5 and CATEGORY_COUNT for 'd' changed to 3. So 'd' is now categorized as INT instead of the desired category PRD (all entries in col c2 for 'd' are positive).
Why did the results of CATEGORY_COUNT change by merely adding the 'distinct' to the outer query?
Thanks for the time to answer this question.I need to categorize the entries in col c1 as follows:
1. if the entry in col c1 has only positive values in col c2, then that entry in col c1 gets a category of PRD.
2. if the entry in col c1 has only negative values in col c2, then that entry in col c1 gets a category of RMT.
3. if the entry in col c1 has both positive and negative values in col c2, then that entry in col c1 gets a category of INT.
Here's the data table:
CREATE TABLE K_TST
C1 VARCHAR2(10),
C2 NUMBER
c1 c2
a 1
a -1
a -3
a 2
a -2
b 1
c -1
d 1
d 2
d 3
So I use the following query:
select a.c1,
a.init_category,
count(*) over (partition by a.c1) category_count,
decode(count(*) over (partition by a.c1), 1, a.init_category, 'INT') final_category
from
select distinct
c1,
decode(instr(to_char(c2), '-'), 0, 'PRD', 'RMT') init_category
from k_tst
) a
The idea is that I assign only categories PRD and RMT in the sub-query and then use the analytical function to count if an entry in col c1 belongs to more than one category. If it belongs to more than one category in the subquery, then the category is reassigned to INT.
No problem, the result is:
C1 INIT_CATEGORY CATEGORY_COUNT FINAL_CATEGORY
a PRD 2 INT
a RMT 2 INT
b PRD 1 PRD
c RMT 1 RMT
d PRD 1 PRD
The report that I want is without INIT_CATEGORY col and only distinct values, so I modify the query from above to this:
select distinct
a.c1,
-- a.init_category,
count(*) over (partition by a.c1) category_count,
decode(count(*) over (partition by a.c1), 1, a.init_category, 'INT') final_category
from
select distinct
c1,
decode(instr(to_char(c2), '-'), 0, 'PRD', 'RMT') init_category
from k_tst
) a
The result is:
C1 CATEGORY_COUNT FINAL_CATEGORY
a 5 INT
b 1 PRD
c 1 RMT
d 3 INT
Note the the CATEGORY_COUNT for 'a' changed to 5 and CATEGORY_COUNT for 'd' changed to 3. So 'd' is now categorized as INT instead of the desired category PRD (all entries in col c2 for 'd' are positive).
Why did the results of CATEGORY_COUNT change by merely adding the 'distinct' to the outer query?
Thanks for the time to answer this question. -
Using analytical functions in procedure
I try to use the Corr Function with an Insert Into Command.
insert into corr_result (CorrVal) select corr(Val1,Val2) from risk_Corr;
when I use it in SQLPlus directly it works.
When I use it in a procedure I got the error message :
PLS-00201: identifier 'CORR' must be declared
ThanksIn order to user Analytical Functions in Pl/Sql you must use them with Dynamic Sql
e.g.,
EXECUTE IMMEDIATE 'insert into corr_result (CorrVal) select corr(Val1,Val2) from risk_Corr ';
I try to use the Corr Function with an Insert Into Command.
insert into corr_result (CorrVal) select corr(Val1,Val2) from risk_Corr;
when I use it in SQLPlus directly it works.
When I use it in a procedure I got the error message :
PLS-00201: identifier 'CORR' must be declared
Thanks -
Lag analytical function and controlling the offset
Can you help me on that? Small challenge. At least I gave up in half a day.
Data
ACCOUNT_NUMBER BATCH_ID TRANSACTION_DATE TRANSACTION_TYPE TRANSACTION_NUMBER PARENT_TRANSACTION_NUMBER
124680 ZY000489 1/11/2011 62 377 NULL
124680 ZY000489 1/11/2011 1 378 NULL
124680 ZY000489 1/11/2011 1 379 NULL
124680 ZY000489 1/11/2011 1 380 NULL
124680 ZY000489 1/11/2011 62 381 NULL
124680 ZY000489 1/11/2011 1 381 NULL
124681 ZY000490 1/11/2011 350 4000 NULL
124681 ZY000490 1/11/2011 1 4001 NULL
124681 ZY000490 1/11/2011 1 4002 NULL
I want to identify parent Transaction Number for each row in above data.
The way to identify it is My parent transaction Id is
- All child transaction have type as 1
- One main transaction can have multiple line items.
- Any transaction (type) can have an related child transaction (Transaction Type as 1)
- Each logical group of transactions have same account number, batch id, transaction date and consecutive Transaction Number (like 377, 378, 379, 380 in above example)
The data should look like below once I identified parent transaction columns:
ACCOUNT_NUMBER BATCH_ID TRANSACTION_DATE TRANSACTION_TYPE TRANSACTION_NUMBER PARENT_TRANSACTION_NUMBER
124680 ZY000489 1/11/2011 62 377 377
124680 ZY000489 1/11/2011 1 378 377
124680 ZY000489 1/11/2011 1 379 377
124680 ZY000489 1/11/2011 1 380 377
124680 ZY000489 1/11/2011 62 381 381
124680 ZY000489 1/11/2011 1 382 381
124681 ZY000490 1/11/2011 350 4000 4000
124681 ZY000490 1/11/2011 1 4001 4000
124681 ZY000490 1/11/2011 1 4002 4000
I tried using LAG Analytical function trying to lag dynamically with offset but had difficulties dynamically expanding the offset. Its an Control Break kind of functionality that i want to achieve in single SQL.
i Know we can do it using pl/sql construct but the challenge is to do it using single sql. Please help
Please let me know if you are able to do it in single SQL.
Thanksrohitgoswami wrote:
Can you help me on that? Small challenge. At least I gave up in half a day.
Data
ACCOUNT_NUMBER BATCH_ID TRANSACTION_DATE TRANSACTION_TYPE TRANSACTION_NUMBER PARENT_TRANSACTION_NUMBER
124680 ZY000489 1/11/2011 62 377 NULL
124680 ZY000489 1/11/2011 1 378 NULL
124680 ZY000489 1/11/2011 1 379 NULL
124680 ZY000489 1/11/2011 1 380 NULL
124680 ZY000489 1/11/2011 62 381 NULL
124680 ZY000489 1/11/2011 1 381 NULL
124681 ZY000490 1/11/2011 350 4000 NULL
124681 ZY000490 1/11/2011 1 4001 NULL
124681 ZY000490 1/11/2011 1 4002 NULL
I want to identify parent Transaction Number for each row in above data.
The way to identify it is My parent transaction Id is
- All child transaction have type as 1
- One main transaction can have multiple line items.
- Any transaction (type) can have an related child transaction (Transaction Type as 1)
- Each logical group of transactions have same account number, batch id, transaction date and consecutive Transaction Number (like 377, 378, 379, 380 in above example)
The data should look like below once I identified parent transaction columns:
ACCOUNT_NUMBER BATCH_ID TRANSACTION_DATE TRANSACTION_TYPE TRANSACTION_NUMBER PARENT_TRANSACTION_NUMBER
124680 ZY000489 1/11/2011 62 377 377
124680 ZY000489 1/11/2011 1 378 377
124680 ZY000489 1/11/2011 1 379 377
124680 ZY000489 1/11/2011 1 380 377
124680 ZY000489 1/11/2011 62 381 381
124680 ZY000489 1/11/2011 1 382 381
124681 ZY000490 1/11/2011 350 4000 4000
124681 ZY000490 1/11/2011 1 4001 4000
124681 ZY000490 1/11/2011 1 4002 4000
I tried using LAG Analytical function trying to lag dynamically with offset but had difficulties dynamically expanding the offset. Its an Control Break kind of functionality that i want to achieve in single SQL.
i Know we can do it using pl/sql construct but the challenge is to do it using single sql. Please help
Please let me know if you are able to do it in single SQL.
ThanksCan probably pretty this up ... i just went for functional code for the moment.
TUBBY_TUBBZ?with
2 data (acc_no, batch_id, trans_date, trans_type, trans_no) as
3 (
4 select 124680, 'ZY000489', to_date('1/11/2011', 'mm/dd/yyyy'), 62 , 377 from dual union all
5 select 124680, 'ZY000489', to_date('1/11/2011', 'mm/dd/yyyy'), 1 , 378 from dual union all
6 select 124680, 'ZY000489', to_date('1/11/2011', 'mm/dd/yyyy'), 1 , 379 from dual union all
7 select 124680, 'ZY000489', to_date('1/11/2011', 'mm/dd/yyyy'), 1 , 380 from dual union all
8 select 124680, 'ZY000489', to_date('1/11/2011', 'mm/dd/yyyy'), 62 , 381 from dual union all
9 select 124680, 'ZY000489', to_date('1/11/2011', 'mm/dd/yyyy'), 1 , 382 from dual union all
10 select 124681, 'ZY000490', to_date('1/11/2011', 'mm/dd/yyyy'), 350 , 4000 from dual union all
11 select 124681, 'ZY000490', to_date('1/11/2011', 'mm/dd/yyyy'), 1 , 4001 from dual union all
12 select 124681, 'ZY000490', to_date('1/11/2011', 'mm/dd/yyyy'), 1 , 4002 from dual
13 )
14 select
15 acc_no,
16 batch_id,
17 trans_date,
18 trans_type,
19 trans_no,
20 case when trans_type != 1
21 then
22 trans_no
23 else
24 lag
25 (
26 case when trans_type = 1
27 then
28 null
29 else
30 trans_no
31 end
32 ignore nulls
33 ) over (partition by acc_no, batch_id, trans_date order by trans_no asc)
34 end as parent_trans_no
35 from data;
ACC_NO BATCH_ID TRANS_DATE TRANS_TYPE TRANS_NO PARENT_TRANS_NO
124680 ZY000489 11-JAN-2011 12 00:00 62 377 377
124680 ZY000489 11-JAN-2011 12 00:00 1 378 377
124680 ZY000489 11-JAN-2011 12 00:00 1 379 377
124680 ZY000489 11-JAN-2011 12 00:00 1 380 377
124680 ZY000489 11-JAN-2011 12 00:00 62 381 381
124680 ZY000489 11-JAN-2011 12 00:00 1 382 381
124681 ZY000490 11-JAN-2011 12 00:00 350 4000 4000
124681 ZY000490 11-JAN-2011 12 00:00 1 4001 4000
124681 ZY000490 11-JAN-2011 12 00:00 1 4002 4000
9 rows selected.
Elapsed: 00:00:00.01
TUBBY_TUBBZ? -
Discoverer Analytic Function windowing - errors and bad aggregation
I posted this first on Database General forum, but then I found this was the place to put it:
Hi, I'm using this kind of windowing function:
SUM(Receitas Especificas) OVER(PARTITION BY Tipo Periodo,Calculado,"Empresa Descrição (Operador)","Empresa Descrição" ORDER BY Ini Periodo RANGE BETWEEN INTERVAL '12' MONTH PRECEDING AND INTERVAL '12' MONTH PRECEDING )
If I use the "Receitas Especificas SUM" instead of
"Receitas Especificas" I get the following error running the report:
"an error occurred while attempting to run..."
This is not in accordance to:
http://www.boku.ac.at/oradoc/ias/10g(9.0.4)/bi.904/b10268.pdf
but ok, the version without SUM inside works.
Another problem is the fact that for analytic function with PARTITION BY,
this does not work (shows the cannot aggregate symbol) if we collapse or use "<All>" in page items.
But it works if we remove the item from the PARTITION BY and also remove from workbook.
It's even worse for windowing functions(query above), because the query
only works if we remove the item from the PARTITION BY but we have to show it on the workbook - and this MAKES NO SENSE... :(
Please help.Unfortunately Discoverer doesn't show (correct) values for analytical functions when selecting "<All>" in a page item. I found out that it does work when you add the analytical function to the db-view instead of to the report as a calculation or as a calculated item on the folder.
The only problem is you've to name all page-items in the PARTITION window, so, when adding a page-item to the report, you,ve to change the db-view and alter the PARTITION window.
Michael -
Understanding row_number() and using it in an analytic function
Dear all;
I have been playing around with row_number and trying to understand how to use it and yet I still cant figure it out...
I have the following code below
create table Employee(
ID VARCHAR2(4 BYTE) NOT NULL,
First_Name VARCHAR2(10 BYTE),
Last_Name VARCHAR2(10 BYTE),
Start_Date DATE,
End_Date DATE,
Salary Number(8,2),
City VARCHAR2(10 BYTE),
Description VARCHAR2(15 BYTE)
insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
values ('01','Jason', 'Martin', to_date('19960725','YYYYMMDD'), to_date('20060725','YYYYMMDD'), 1234.56, 'Toronto', 'Programmer');
insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
values('02','Alison', 'Mathews', to_date('19760321','YYYYMMDD'), to_date('19860221','YYYYMMDD'), 6661.78, 'Vancouver','Tester')
insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
values('03','James', 'Smith', to_date('19781212','YYYYMMDD'), to_date('19900315','YYYYMMDD'), 6544.78, 'Vancouver','Tester')
insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
values('04','Celia', 'Rice', to_date('19821024','YYYYMMDD'), to_date('19990421','YYYYMMDD'), 2344.78, 'Vancouver','Manager')
insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
values('05','Robert', 'Black', to_date('19840115','YYYYMMDD'), to_date('19980808','YYYYMMDD'), 2334.78, 'Vancouver','Tester')
insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
values('06','Linda', 'Green', to_date('19870730','YYYYMMDD'), to_date('19960104','YYYYMMDD'), 4322.78,'New York', 'Tester')
insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
values('07','David', 'Larry', to_date('19901231','YYYYMMDD'), to_date('19980212','YYYYMMDD'), 7897.78,'New York', 'Manager')
insert into Employee(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
values('08','James', 'Cat', to_date('19960917','YYYYMMDD'), to_date('20020415','YYYYMMDD'), 1232.78,'Vancouver', 'Tester')I did a simple select statement
select * from Employee e
and it returns this below
ID FIRST_NAME LAST_NAME START_DAT END_DATE SALARY CITY DESCRIPTION
01 Jason Martin 25-JUL-96 25-JUL-06 1234.56 Toronto Programmer
02 Alison Mathews 21-MAR-76 21-FEB-86 6661.78 Vancouver Tester
03 James Smith 12-DEC-78 15-MAR-90 6544.78 Vancouver Tester
04 Celia Rice 24-OCT-82 21-APR-99 2344.78 Vancouver Manager
05 Robert Black 15-JAN-84 08-AUG-98 2334.78 Vancouver Tester
06 Linda Green 30-JUL-87 04-JAN-96 4322.78 New York Tester
07 David Larry 31-DEC-90 12-FEB-98 7897.78 New York Manager
08 James Cat 17-SEP-96 15-APR-02 1232.78 Vancouver TesterI wrote another select statement with row_number. see below
SELECT first_name, last_name, salary, city, description, id,
ROW_NUMBER() OVER(PARTITION BY description ORDER BY city desc) "Test#"
FROM employee
and I get this result
First_name last_name Salary City Description ID Test#
Celina Rice 2344.78 Vancouver Manager 04 1
David Larry 7897.78 New York Manager 07 2
Jason Martin 1234.56 Toronto Programmer 01 1
Alison Mathews 6661.78 Vancouver Tester 02 1
James Cat 1232.78 Vancouver Tester 08 2
Robert Black 2334.78 Vancouver Tester 05 3
James Smith 6544.78 Vancouver Tester 03 4
Linda Green 4322.78 New York Tester 06 5
I understand the partition by which means basically for each associated group a unique number wiill be assigned for that row, so in this case since tester is one group, manager is another group, and programmer is another group then tester gets its own unique number for each row, manager as well and etc.What is throwing me off is the order by and how this numbering are assigned. why is
1 assigned to Alison Mathews for the tester group and 2 assigned to James Cat and 3 assigned Robert Black
I apologize if this is a stupid question, i have tried reading about it online and looking at the oracle documentation but that still dont fully understand why.user13328581 wrote:
understanding row_number() and using it in an analytic functionROW_NUMBER () IS an analytic fucntion. Are you trying to use the results of ROW_NUMBER in another analytic function? If so, you need a sub-query. Analuytic functions can't be nested within other analytic functions.
...I have the following code below
... I did a simple select statementThanks for posting all that! It's really helpful.
... and I get this result
First_name last_name Salary City Description ID Test#
Celina Rice 2344.78 Vancouver Manager 04 1
David Larry 7897.78 New York Manager 07 2
Jason Martin 1234.56 Toronto Programmer 01 1
Alison Mathews 6661.78 Vancouver Tester 02 1
James Cat 1232.78 Vancouver Tester 08 2
Robert Black 2334.78 Vancouver Tester 05 3
James Smith 6544.78 Vancouver Tester 03 4
Linda Green 4322.78 New York Tester 06 5... What is throwing me off is the order by and how this numbering are assigned. why is
1 assigned to Alison Mathews for the tester group and 2 assigned to James Cat and 3 assigned Robert Black That's determined by the analytic ORDER BY clause. Yiou said "ORDER BY city desc", so a row where city='Vancouver' will get a lower namber than one where city='New York', since 'Vancouver' comes after 'New York' in alphabetic order.
If you have several rows that all have the same city, then you can be sure that ROW_NUMBER will assign them consecutive numbers, but it's arbitrary which one of them will be lowest and which highest. For example, you have 5 'Tester's: 4 from Vancouver and 1 from New York. There's no particular reason why the one with first_name='Alison' got assinge 1, and 'James' got #2. If you run the same query again, without changing the table at all, then 'Robert' might be #1. It's certain that the 4 Vancouver rows will be assigned numbers 1 through 4, but there's no way of telling which of those 4 rows will get which of those 4 numbers.
Similar to a query's ORDER BY clause, the analytic ORDER BY clause can have two or more expressions. The N-th one will only be considered if there was a tie for all (N-1) earlier ones. For example "ORDER BY city DESC, last_name, first_name" would mena 'Vancouver' comes before 'New York', but, if multiple rows all have city='Vancouver', last_name would determine the order: 'Black' would get a lower number than 'Cat'. If you had multiple rows with city='Vancouver' and last_name='Black', then the order would be determined by first_name. -
COUNT(DISTINCT) WITH ORDER BY in an analytic function
-- I create a table with three fields: Name, Amount, and a Trans_Date.
CREATE TABLE TEST
NAME VARCHAR2(19) NULL,
AMOUNT VARCHAR2(8) NULL,
TRANS_DATE DATE NULL
-- I insert a few rows into my table:
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Anna', '110', TO_DATE('06/01/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Anna', '20', TO_DATE('06/01/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Anna', '110', TO_DATE('06/02/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Anna', '21', TO_DATE('06/03/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Anna', '68', TO_DATE('06/04/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Anna', '110', TO_DATE('06/05/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Anna', '20', TO_DATE('06/06/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Bill', '43', TO_DATE('06/01/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Bill', '77', TO_DATE('06/02/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Bill', '221', TO_DATE('06/03/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Bill', '43', TO_DATE('06/04/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
INSERT INTO TEST ( TEST.NAME, TEST.AMOUNT, TEST.TRANS_DATE ) VALUES ( 'Bill', '73', TO_DATE('06/05/2005 08:00:00 PM', 'MM/DD/YYYY HH12:MI:SS PM') );
commit;
/* I want to retrieve all the distinct count of amount for every row in an analytic function with COUNT(DISTINCT AMOUNT) sorted by name and ordered by trans_date where I get only calculate for the last four trans_date for each row (i.e., for the row "Anna 110 6/5/2005 8:00:00.000 PM," I only want to look at the previous dates from 6/2/2005 to 6/5/2005 and get the distinct count of how many amounts there are different for Anna). Note, I cannot use the DISTINCT keyword in this query because it doesn't work with the ORDER BY */
select NAME, AMOUNT, TRANS_DATE, COUNT(/*DISTINCT*/ AMOUNT) over ( partition by NAME
order by TRANS_DATE range between numtodsinterval(3,'day') preceding and current row ) as COUNT_AMOUNT
from TEST t;
This is the results I get if I just count all the AMOUNT without using distinct:
NAME AMOUNT TRANS_DATE COUNT_AMOUNT
Anna 110 6/1/2005 8:00:00.000 PM 2
Anna 20 6/1/2005 8:00:00.000 PM 2
Anna 110 6/2/2005 8:00:00.000 PM 3
Anna 21 6/3/2005 8:00:00.000 PM 4
Anna 68 6/4/2005 8:00:00.000 PM 5
Anna 110 6/5/2005 8:00:00.000 PM 4
Anna 20 6/6/2005 8:00:00.000 PM 4
Bill 43 6/1/2005 8:00:00.000 PM 1
Bill 77 6/2/2005 8:00:00.000 PM 2
Bill 221 6/3/2005 8:00:00.000 PM 3
Bill 43 6/4/2005 8:00:00.000 PM 4
Bill 73 6/5/2005 8:00:00.000 PM 4
The COUNT_DISTINCT_AMOUNT is the desired output:
NAME AMOUNT TRANS_DATE COUNT_DISTINCT_AMOUNT
Anna 110 6/1/2005 8:00:00.000 PM 1
Anna 20 6/1/2005 8:00:00.000 PM 2
Anna 110 6/2/2005 8:00:00.000 PM 2
Anna 21 6/3/2005 8:00:00.000 PM 3
Anna 68 6/4/2005 8:00:00.000 PM 4
Anna 110 6/5/2005 8:00:00.000 PM 3
Anna 20 6/6/2005 8:00:00.000 PM 4
Bill 43 6/1/2005 8:00:00.000 PM 1
Bill 77 6/2/2005 8:00:00.000 PM 2
Bill 221 6/3/2005 8:00:00.000 PM 3
Bill 43 6/4/2005 8:00:00.000 PM 3
Bill 73 6/5/2005 8:00:00.000 PM 4
Thanks in advance.you can try to write your own udag.
here is a fake example, just to show how it "could" work. I am here using only 1,2,4,8,16,32 as potential values.
create or replace type CountDistinctType as object
bitor_number number,
static function ODCIAggregateInitialize(sctx IN OUT CountDistinctType)
return number,
member function ODCIAggregateIterate(self IN OUT CountDistinctType,
value IN number) return number,
member function ODCIAggregateTerminate(self IN CountDistinctType,
returnValue OUT number, flags IN number) return number,
member function ODCIAggregateMerge(self IN OUT CountDistinctType,
ctx2 IN CountDistinctType) return number
create or replace type body CountDistinctType is
static function ODCIAggregateInitialize(sctx IN OUT CountDistinctType)
return number is
begin
sctx := CountDistinctType('');
return ODCIConst.Success;
end;
member function ODCIAggregateIterate(self IN OUT CountDistinctType, value IN number)
return number is
begin
if (self.bitor_number is null) then
self.bitor_number := value;
else
self.bitor_number := self.bitor_number+value-bitand(self.bitor_number,value);
end if;
return ODCIConst.Success;
end;
member function ODCIAggregateTerminate(self IN CountDistinctType, returnValue OUT
number, flags IN number) return number is
begin
returnValue := 0;
for i in 0..log(2,self.bitor_number) loop
if (bitand(power(2,i),self.bitor_number)!=0) then
returnValue := returnValue+1;
end if;
end loop;
return ODCIConst.Success;
end;
member function ODCIAggregateMerge(self IN OUT CountDistinctType, ctx2 IN
CountDistinctType) return number is
begin
return ODCIConst.Success;
end;
end;
CREATE or REPLACE FUNCTION CountDistinct (n number) RETURN number
PARALLEL_ENABLE AGGREGATE USING CountDistinctType;
drop table t;
create table t as select rownum r, power(2,trunc(dbms_random.value(0,6))) p from all_objects;
SQL> select r,p,countdistinct(p) over (order by r) d from t where rownum<10 order by r;
R P D
1 4 1
2 1 2
3 8 3
4 32 4
5 1 4
6 16 5
7 16 5
8 4 5
9 4 5buy some good book if you want to start at writting your own "distinct" algorythm.
Message was edited by:
Laurent Schneider
a simpler but memory killer algorithm would use a plsql table in an udag and do the count(distinct) over that table to return the value -
GROUP BY and analytical functions
Hi all,
I need your help with grouping my data.
Below you can see sample of my data (in my case I have view where data is in almost same format).
with test_data as(
select '01' as code, 'SM' as abbreviation, 1010 as groupnum, 21 as pieces, 4.13 as volume, 3.186 as avgvolume from dual
union
select '01' as code, 'SM' as abbreviation, 2010 as groupnum, 21 as pieces, 0 as volume, 3.186 as avgvolume from dual
union
select '01' as code, 'SM' as abbreviation, 3000 as groupnum, 21 as pieces, 55 as volume, 3.186 as avgvolume from dual
union
select '01' as code, 'SM' as abbreviation, 3010 as groupnum, 21 as pieces, 7.77 as volume, 3.186 as avgvolume from dual
union
select '02' as code, 'SMP' as abbreviation, 1010 as groupnum, 30 as pieces, 2.99 as volume, 0.1 as avgvolume from dual
union
select '03' as code, 'SMC' as abbreviation, 1010 as groupnum, 10 as pieces, 4.59 as volume, 0.459 as avgvolume from dual
union
select '40' as code, 'DB' as abbreviation, 1010 as groupnum, 21 as pieces, 5.28 as avgvolume, 0.251 as avgvolume from dual
select
DECODE (GROUPING (code), 1, 'report total:', code) as code,
abbreviation as abbreviation,
groupnum as pricelistgrp,
sum(pieces) as pieces,
sum(volume) as volume,
sum(avgvolume) as avgvolume
--sum(sum(distinct pieces)) over (partition by code,groupnum) as piecessum,
--sum(volume) volume,
--round(sum(volume) / 82,3) as avgvolume
from test_data
group by grouping sets((code,abbreviation,groupnum,pieces,volume,avgvolume),null)
order by 1,3;Select statement which I have written returns the output below:
CODE ABBR GRPOUP PIECES VOLUME AVGVOL
01 SM 1010 21 4.13 3.186
01 SM 2010 21 0 3.186
01 SM 3000 21 55 3.186
01 SM 3010 21 7.77 3.186
02 SMP 1010 30 2.99 0.1
03 SMC 1010 10 4.59 0.459
40 DB 1010 21 5.28 0.251
report total: 145 79.76 13.554Number of pieces and avg volume is same for same codes (01 - pieces = 21, avgvolume = 3.186 etc.)
What I need is to get output like below:
CODE ABBR GRPOUP PIECES VOLUME AVGVOL
01 SM 1010 21 4.13 3.186
01 SM 2010 21 0 3.186
01 SM 3000 21 55 3.186
01 SM 3010 21 7.77 3.186
02 SMP 1010 30 2.99 0.1
03 SMC 1010 10 4.59 0.459
40 DB 1010 21 5.28 0.251
report total: 82 79.76 0.973Where total number of pieces is computed as sum of distinct numbers of pieces for each code -> *82 = 21 + 30 + 10 +21*.
Total volume is just sum of volumes in each row -> *79.76 = 4.13+0+55+7.77+2.99+4.59+5.28*.
And Average volume is computed as total volume / total number of pieces -> *0.973 = 79.76 / 82*.
I was trying to use analytical function (sum() over (partition by)) to get desired output, but without good results.
Could anyone help me with this issue?
Thanks in advance!
Regards,
JiriHi, Jiri,
Jiri N. wrote:
Hi all,
I need your help with grouping my data.
Below you can see sample of my data (in my case I have view where data is in almost same format).I assume the view guarantees that all rows with the same code (or the same code and groupnum) will always have the same pieces and the same avgvolume.
with test_data as( ...Thanks for posting this; it's very helpful.
What I need is to get output like below:
CODE ABBR GRPOUP PIECES VOLUME AVGVOL
01 SM 1010 21 4.13 3.186
01 SM 2010 21 0 3.186
01 SM 3000 21 55 3.186
01 SM 3010 21 7.77 3.186
02 SMP 1010 30 2.99 0.1
03 SMC 1010 10 4.59 0.459
40 DB 1010 21 5.28 0.251
report total: 82 79.76 0.973
Except for the last row, you're just displaying data straight from the table (or view).
It might be easier to get the results you want uisng a UNION. One branch of the UNION would get the"report total" row, and the other branch would get all the rest.
>
Where total number of pieces is computed as sum of distinct numbers of pieces for each code -> *82 = 21 + 30 + 10 +21*.It's not just distinct numbers. In this example, two different codes have pieces=21, so the total of distinct pieces is 61 = 21 + 30 + 10.
>
Total volume is just sum of volumes in each row -> *79.76 = 4.13+0+55+7.77+2.99+4.59+5.28*.
And Average volume is computed as total volume / total number of pieces -> *0.973 = 79.76 / 82*.
I was trying to use analytical function (sum() over (partition by)) to get desired output, but without good results. I would use nested aggregate functions to do that:
SELECT code
, abbreviation
, groupnum AS pricelistgrp
, pieces
, volume
, avgvolume
FROM test_data
UNION ALL
SELECT 'report total:' AS code
, NULL AS abbreviaion
, NULL AS pricelistgrp
, SUM (MAX (pieces)) AS pieces
, SUM (SUM (volume)) AS volume
, SUM (SUM (volume))
/ SUM (MAX (pieces)) AS avgvolume
FROM test_data
GROUP BY code -- , abbreviation?
ORDER BY code
, pricelistgrp
;Output:
CODE ABB PRICELISTGRP PIECES VOLUME AVGVOLUME
01 SM 1010 21 4.13 3.186
01 SM 2010 21 0.00 3.186
01 SM 3000 21 55.00 3.186
01 SM 3010 21 7.77 3.186
02 SMP 1010 30 2.99 .100
03 SMC 1010 10 4.59 .459
40 DB 1010 21 5.28 .251
report total: 82 79.76 .973It's unclear if you want to GROUP BY just code (like I did above) or by both code and abbreviation.
Given that this data is coming from a view, it might be simpler and/or more efficient to make separate version of the view, or to replicate most of the view in a query. -
how to ignore nulls in analytic functions ( row_number() and count())
Iam attaching test data can any one help me please
thanks in advanceeeee
CREATE TABLE TEMP_table
ACCTNUM NUMBER,
l_DATE TIMESTAMP(3),
CODE VARCHAR2(35 BYTE),
VENDOR VARCHAR2(35 BYTE)
insert into temp_table values (1,sysdate+1/60,'bso','v1');
insert into temp_table values (1,sysdate+2/60,'bsof','v1');
insert into temp_table values (1,sysdate+3/60,'bsof','v2');
insert into temp_table values (1,sysdate+4/60,'','v1');
ian executing this my ;
SELECT acctnum,l_date,vendor,code_1,
CASE
WHEN code = 'bsof'
AND COUNT (DISTINCT code) OVER (PARTITION BY acctnum, vendor) > 1
AND row_number () OVER (PARTITION BY acctnum, vendor ORDER BY vendor, l_date) != 1
THEN 'yes'
ELSE 'no' END result
FROM (select acctnum,l_date,vendor, code code_1, case when code IN ('bso', 'bsof') then code
else null end code from TEMP_TABLE
ORDER BY acctnum ,l_date);
my result :
1 3/23/2011 5:24:34.000 PM v1 bso no
1 3/23/2011 5:48:36.000 PM v1 bsof yes
1 3/23/2011 6:36:41.000 PM v1 bsof yes
1 3/24/2011 11:55:53.000 AM v1 no
1 3/23/2011 6:12:38.000 PM v2 bsof no
I need to eliminate nulls in top query not in inner query (not using where condition in inner query)
[\code] -
Analytic function and aggregate function
What are analytic function and aggregate function. What is difference between them?
hi,
Analytic Functions :----------
Analytic functions compute an aggregate value based on a group of rows. They differ from aggregate functions in that they return multiple rows for each group. The group of rows is called a window and is defined by the analytic_clause. For each row, a sliding window of rows is defined. The window determines the range of rows used to perform the calculations for the current row. Window sizes can be based on either a physical number of rows or a logical interval such as time.
Analytic functions are the last set of operations performed in a query except for the final ORDER BY clause. All joins and all WHERE, GROUP BY, and HAVING clauses are completed before the analytic functions are processed. Therefore, analytic functions can appear only in the select list or ORDER BY clause.
Analytic functions are commonly used to compute cumulative, moving, centered, and reporting aggregates.
Aggregate Functions :----------
Aggregate functions return a single result row based on groups of rows, rather than on single rows. Aggregate functions can appear in select lists and in ORDER BY and HAVING clauses. They are commonly used with the GROUP BY clause in a SELECT statement, where Oracle Database divides the rows of a queried table or view into groups. In a query containing a GROUP BY clause, the elements of the select list can be aggregate functions, GROUP BY expressions, constants, or expressions involving one of these. Oracle applies the aggregate functions to each group of rows and returns a single result row for each group.
If you omit the GROUP BY clause, then Oracle applies aggregate functions in the select list to all the rows in the queried table or view. You use aggregate functions in the HAVING clause to eliminate groups from the output based on the results of the aggregate functions, rather than on the values of the individual rows of the queried table or view.
let me know if you are feeling any problem in understanding.
thanks.
Edited by: varun4dba on Jan 27, 2011 3:32 PM -
Understanding sum() over(order by) analytic function
Could you please explain Having_order_by column values computation for below query?
I understand that No_Partition column has been computed over entire result set
select level
,sum(level) over(order by level) Having_order_by
,sum(level) over() No_Partition
from dual
connect by level < 6Hi,
ActiveSomeTimes wrote:
Could you please explain Having_order_by column values computation for below query?
I understand that No_Partition column has been computed over entire result set
select level
,sum(level) over(order by level) Having_order_by
,sum(level) over() No_Partition
from dual
connect by level < 6
When you have an ORDER BY clause, the function only operates on a window, that is, a subset of the result set, relative to the current row.
When you say "ORDER BY LEVEL", it will only operate on LEVELs less that or equal to the current LEVEL, so on
LEVEL = 1, the analytic fucntion will only look at LEVEL <= 1, that is, just 1; on
LEVEL = 2, the analytic fucntion will only look at LEVEL <= 2, that is, 1 and 2; on
LEVEL = 3, the analytic fucntion will only look at LEVEL <= 3, that is, 1, 2 and 3
LEVEL = 6, the analytic fucntion will only look at LEVEL <= 6, that is, 1, 2, 3, 4, 5 and 6
In the function call without the ORDER BY clause, the function looks at the entire result set, regrdless of what vlaue LEVEL has on the current row. -
OLAP Expression Analytical Functions and NA Values
Hello,
I am trying to use the SUM and MAX functions over a hierarchy where there are potentially NA values. I believe in OLAP DML, the natural behavior is to skip these values. Can a skip be accomplished with either the SUM or MAX OLAP Expression Syntax functions?
Cheers!Pre-requisites:
===============
Time dimension with level=DAY.... i have restricted data to 1 month approx.. 20100101 to 20100201 (32 days).
Measure of interest - a (say)
Time Dimension attribute which indicates WEEKDAY.... if you have END_DATE attribute with date datatype so we can extract the DAY (MON/TUE/WED/...) from it and decipher wkday/wkend status for DAY.
Sort time as per END_DATE ..
Take care of other dimensions during testing... restrict all other dimensions of cube to single value. Final formula would be independent of other dimensions but this helps development/testing.
Step 1:
======
"Firm up the required design in olap dml
"rpr down time
" w 10 heading 't long' time_long_description
" w 10 heading 't end date' time_end_date
" w 20 heading 'Day Type' convert(time_end_date text 'DY')
" a
NOTE: version 1 of moving total
" heading 'moving minus 2 all' movingtotal(a, -2, 0, 1, time status)
" w 20 heading 'Day Type' convert(time_end_date text 'DY')
" heading 'a wkday' if convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN' then a else na
NOTE: version 2 of moving total
" heading 'moving minus 2 wkday' movingtotal(a, -2, 0, 1, time convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN')
" w 20 heading 'Day Type' convert(time_end_date text 'DY')
" heading 'a wkday non-na' if convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN' and a ne na then a else na
NOTE: version 3 of moving total
" heading 'moving minus 2 wkday non-na' movingtotal(a, -2, 0, 1, time convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN' and a ne na)
OLAP DML Command:
rpr down time w 10 heading 't long' time_long_description w 10 heading 't end date' time_end_date w 20 heading 'Day Type' convert(time_end_date text 'DY') a heading 'moving minus 2 all' movingtotal(a, -2, 0, 1, time status) w 20 heading 'Day Type' convert(time_end_date text 'DY') heading 'a wkday' if convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN' then a else na heading 'moving minus 2 wkday' movingtotal(a, -2, 0, 1, time convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN') w 20 heading 'Day Type' convert(time_end_date text 'DY') heading 'a wkday non-na' if convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN' and a ne na then a else na heading 'moving minus 2 wkday non-na' movingtotal(a, -2, 0, 1, time convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN' and a ne na)
Step 2:
======
"Define additional measure to contain the required/desired formula implementing the business requirements (version 3 above)
" create formula AF1 which points to last column... i.e. OLAP_DML_EXPRESSION
dfn af1 formula movingtotal(a, -2, 0, 1, time convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN' and a ne na)
"NOTE: Do this via AWM using calculated member with template type = OLAP_DML_EXPRESSION so that the cube view for cube contains a column for measure AF1
OLAP DML Command:
rpr down time w 10 heading 't long' time_long_description w 10 heading 't end date' time_end_date w 20 heading 'Day Type' convert(time_end_date text 'DY') a heading 'a wkday non-na' if convert(time_end_date text 'DY') ne 'SAT' and convert(time_end_date text 'DY') ne 'SUN' and a ne na then a else na heading 'moving minus 2 wkday non-na (AF1)' af1
->
Step 3:
=======
Extend Oracle OLAP with regular SQL functionality like SQL ANALYTICAL functions to fill up the gaps for intermediate week days like DAY_20100104 (TUE), DAY_20100105 (WED) etc.
Use: SQL Analytical Function LAST_VALUE() in query.. i.e. in report or query.. dont use AF1 but use LAST_VALUE(af1).... as below pseudo-code:
LAST_VALUE(cube_view.af1) over (partition by <product, organization, ... non-time dimensions> order by <DAY_KEY_Col> range unbounded preceeding and current row)
HTH
Shankar
Maybe you are looking for
-
How do I open a pdf file on my iPad with Adobe reader.
I can't open a pdf file in an email with Adobe reader.
-
PSE 13: Disabling Crop Suggestions
In an attempt to disable Crop Suggestions in PSE 13 on my PC running Windows 7, I went to Edit/Preferences/General and unchecked the box labeled Enable Crop Preselection. This action did not disable crop suggestions. Is there something else I can do
-
Airplay lag only on iMac.
So after searching through tons and tons of posts, and all over the internet. I still cannot work out, why I only get lag when airplaying from iMac. My iPhone 5s, iPhone 6, iPad mini and air 2, no lag at all. I can Airplay across the house, with thes
-
Organizational Management: Concept of Central Person
Hi, Could you please explain the concept of Central Person? I see in an organization, the central person has a relationship with that of a PERSON and POSITION. Kindly let me know the relevant documents of same. Thank you. Regards, Dinu
-
I used my iPod yesterday, and it was charged. I put it on the floor, and took it into my room before I went to bed. I wanted to check what I missed while I wasn't using it, but it was "off". I put it on the charger, and it should've been charged up b