FIRST_VALUE & LAST_VALUE
Given the following sample data:
AverageRate CurrencyDate
1.0001 2001-09-03
1.0001 2001-09-04
1.0002 2001-09-05
1.0002 2001-09-06
1.0005 2001-09-07
1.0005 2001-09-08
1.0005 2001-09-09
1.0001 2001-09-10
1.0002 2001-09-11
1.0002 2001-09-12
How can I, using FIRST_VALUE and LAST_VALUE, return the desired output:
AverageRate From To
1.0001 2001-09-03 2001-09-04
1.0002 2001-09-05 2001-09-06
1.0005 2001-09-07 2001-09-09
1.0001 2001-09-10 2001-09-10
1.0002 2001-09-11 2001-09-12
I know how to do this using min/max, self joins and row_number() with partition by, but surely with 2012 there is a simpler (and more optimized) solution which only requires one select statement. Are my expectations too much?
First_Value, Lag, Lead, ROWS, and RANGE are great additions (Oracle still has more cool analytic functions than SQL server though), but they won't necessarily magically solve all problems. If your data didn't have the unusual position related duplicates
(where 1.0002 showed up again later in the list, but is a different group to the first time through), your query might have fit 100 percent nicely into a less complex First_Value scenario.
Here's a way that takes care of it, that does use new SQL 2012 feature ROWS and also FIRST_VALUE. The key element is the "ROWS" clause, where we were able to limit the window to rows that occurred BEFORE the current row. Then FIRST_VALUE
at the final select statement too.
Create_Testdata:
Declare @Tbl table (avgrate decimal(9,4), currdate date)
Insert @Tbl Select 1.0001, '2001-09-03'
Insert @Tbl Select 1.0001, '2001-09-04'
Insert @Tbl Select 1.0002, '2001-09-05'
Insert @Tbl Select 1.0002, '2001-09-06'
Insert @Tbl Select 1.0005, '2001-09-07'
Insert @Tbl Select 1.0005, '2001-09-08'
Insert @Tbl Select 1.0005, '2001-09-09'
Insert @Tbl Select 1.0001, '2001-09-10'
Insert @Tbl Select 1.0002, '2001-09-11'
Insert @Tbl Select 1.0002, '2001-09-12'
Lister:
With L1_RowNums_Lead_Lag as
Select *
, row_number() over(order by @@Servername) as RN
, lead(avgrate) over(order by @@servername) as NextRate
, lag(avgrate) over(order by @@servername) as PrevRate
From @Tbl
, L2_RowFamily as
Select *
, case When (Prevrate <> avgrate and NextRate <> Avgrate) then RN
when NextRate = AvgRate and IsNull(PrevRate, -1) <> AvgRate then RN
Else NULL
End as RowFamily
From L1_RowNums_Lead_Lag
, L3_RowFamily_Assign as
Select *
, case when RowFamily is Null
Then Max(RowFamily) over(partition by avgrate order by rn Rows between unbounded preceding and current row)
Else RowFamily
End as RowFamily_All
from L2_RowFamily
, L4_Final as
Select *
, first_Value(Currdate) over(partition by RowFamily_all order by RowFamily_all) as FirstCurrdate
, Last_Value(Currdate) over(partition by RowFamily_all order by RowFamily_all) as LastCurrdate
From L3_RowFamily_Assign
Select * from L4_Final /* Where clause has to be in final query */
where RowFamily is not null
order by RN;
Results match your posted desired results.
Similar Messages
-
FIRST_VALUE,LAST_VALUE,invalid_identifier
Hello,
I am converting the ACCESS scripts to ORACLE sql. There is FIRST function in Access script. I converted in oracle sql language, but oracle gives an error as "invalid identifier" that I can not understand the reason.
If you will help to solve this problem, I am really really appreciate.
Access query:
select
First([Reporting Comps].COMPCODE) AS Cage,
Last(IIf([Reporting Comps]![COMPCODE] Is Not Null,[Reporting Comps]![compcode],"")) AS MFR,
First(COMPANIES.COMPANY_NAME) AS FirstOfCOMPANY_NAME,
First(COMPANIES.COMPANY_CODE) AS FirstOfCOMPANY_CODE,
Last(IIf([Reporting Comps_1]![COMPCODE] Is Not Null,[Reporting Comps_1]![compcode],"")) AS 2MFR,
First(COMPANIES_2.COMPANY_NAME) AS FirstOfCOMPANY_NAME1,
First([Reporting Comps_2].COMPCODE) AS 3MFR,
IIf([MFR] Is Not Null,[MFR],IIf([3MFR] Is Not Null,[3MFR],IIf([2MFR] Is Not Null,[2MFR],"Others"))) AS M
My script for oracle:
SELECT X,Y,Z,
FIRST_VALUE(BI_Reporting_Comps.COMPCODE) OVER ( ORDER BY IND_AUTO_KEY ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) CAGE,
LAST_VALUE(CASE WHEN BI_REPORTING_COMPS.COMPCODE IS NOT NULL THEN BI_REPORTING_COMPS.COMPCODE ELSE NULL END) OVER ( ORDER BY IND_AUTO_KEY ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) MFR,
FIRST_VALUE(COMPANIES.COMPANY_NAME) OVER ( ORDER BY IND_AUTO_KEY ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FirstOfCOMPANY_NAME,
FIRST_VALUE(COMPANIES.COMPANY_CODE) OVER ( ORDER BY IND_AUTO_KEY ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FirstOfCOMPANY_CODE,
LAST_VALUE(CASE WHEN BI_REPORTING_COMPS.COMPCODE IS NOT NULL THEN BI_REPORTING_COMPS.COMPCODE ELSE NULL END) OVER ( ORDER BY IND_AUTO_KEY ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) MFR2,
FIRST_VALUE(COMPANIES.COMPANY_NAME) OVER ( ORDER BY IND_AUTO_KEY ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FirstOfCOMPANY_NAME1,
CASE WHEN MFR Is Not Null THEN MFR
WHEN MFR2 Is Not Null THEN MFR2
WHEN MF3 Is Not Null THEN MFR3
ELSE 'OTHERS'
END AS MANUFACTURER
FROM .............
GROUP BY
X,
Y,
Z,
CASE WHEN MFR Is Not Null THEN MFR
WHEN MFR2 Is Not Null THEN MFR2
WHEN MF3 Is Not Null THEN MFR3
ELSE 'OTHERS'
END
ORDER BY IND_AUTO_KEY ASC;Hello
I've reformatted your code to make it more readable. When you post code please remember to use the {noformat}{noformat} tag before and after to ensure the formatting is preserved.SELECT BI_INVOICES.REPORTED_IN,
BI_Invoices.IND_AUTO_KEY,
BI_Invoices.Invoice,
BI_Invoices.Customer,
BI_Invoices."P/N",
BI_Invoices.Qty_Ship,
BI_Invoices.Unit_Cost,
BI_Invoices.Unit_Sell,
BI_Invoices.Total_Cost,
BI_Invoices.Total_Sales,
CASE
WHEN BI_INVOICES.END_DEST1 '@'--<MISSING OPERATOR
THEN BI_INVOICES.END_DEST1
WHEN BI_INV_DEST_REF_1.DEST IS NOT NULL THEN BI_INV_DEST_REF_1.DEST
ELSE bi_inv_dest_ref_2.destination
END
AS End_Dest,
BI_Invoices.End_App,
BI_Invoices.Salesperson,
BI_Invoices.SOD_AUTO_KEY,
FIRST_VALUE (
BI_Reporting_Comps.COMPCODE)
OVER (ORDER BY BI_INVOICES.IND_AUTO_KEY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
Cage,
LAST_VALUE (
CASE
WHEN BI_REPORTING_COMPS.COMPCODE IS NOT NULL
THEN
BI_REPORTING_COMPS.COMPCODE
ELSE
END)
OVER (ORDER BY BI_INVOICES.IND_AUTO_KEY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
MFR1,
FIRST_VALUE (
COMPANIES.COMPANY_NAME)
OVER (ORDER BY BI_INVOICES.IND_AUTO_KEY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FirstOfCOMPANY_NAME,
LAST_VALUE (
CASE
WHEN BI_REPORTING_COMPS.COMPCODE IS NOT NULL
THEN
BI_REPORTING_COMPS.COMPCODE
ELSE
END)
OVER (ORDER BY BI_INVOICES.IND_AUTO_KEY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
MFR2,
FIRST_VALUE (
COMPANIES.COMPANY_NAME)
OVER (ORDER BY BI_INVOICES.IND_AUTO_KEY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FirstOfCOMPANY_NAME1,
FIRST_VALUE (
BI_Reporting_Comps.COMPCODE)
OVER (ORDER BY BI_INVOICES.IND_AUTO_KEY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
MFR3
FROM QCTL.STOCK
LEFT JOIN QCTL.PO_DETAIL
ON QCTL.STOCK.POD_AUTO_KEY = QCTL.PO_DETAIL.POD_AUTO_KEY
LEFT JOIN QCTL.PO_HEADER
ON QCTL.PO_DETAIL.POH_AUTO_KEY = QCTL.PO_HEADER.POH_AUTO_KEY
AND QCTL.STOCK.ORIGINAL_PO_NUMBER = QCTL.PO_HEADER.PO_NUMBER
LEFT JOIN QCTL.RO_DETAIL
ON QCTL.STOCK.ROD_AUTO_KEY = QCTL.RO_DETAIL.ROD_AUTO_KEY
LEFT JOIN QCTL.RO_HEADER
ON QCTL.RO_DETAIL.ROH_AUTO_KEY = QCTL.RO_HEADER.ROH_AUTO_KEY
LEFT JOIN QCTL.COMPANIES
ON QCTL.PO_HEADER.CMP_AUTO_KEY = QCTL.COMPANIES.CMP_AUTO_KEY
AND QCTL.RO_HEADER.CMP_AUTO_KEY = QCTL.COMPANIES.CMP_AUTO_KEY
LEFT JOIN BI_REPORTING_COMPS
ON QCTL.COMPANIES.CMP_AUTO_KEY = BI_REPORTING_COMPS.CMP_AUTO_KEY
RIGHT JOIN QCTL.STOCK_RESERVATIONS
ON QCTL.STOCK_RESERVATIONS.STM_AUTO_KEY = QCTL.STOCK.STM_AUTO_KEY
RIGHT JOIN BI_INVOICES
ON BI_INVOICES.SOD_AUTO_KEY = QCTL.STOCK_RESERVATIONS.SOD_AUTO_KEY
LEFT JOIN BI_INV_DEST_REF_2
ON BI_INVOICES.INVOICE = BI_INV_DEST_REF_2.DESTINATION
LEFT JOIN BI_INV_DEST_REF_1
ON BI_INVOICES.INVOICE = BI_INV_DEST_REF_1.INVOICE
GROUP BY BI_INVOICES.REPORTED_IN,
BI_Invoices.IND_AUTO_KEY,
BI_Invoices.Invoice,
BI_Invoices.Customer,
BI_Invoices."P/N",
BI_Invoices.Qty_Ship,
BI_Invoices.Unit_Cost,
BI_Invoices.Unit_Sell,
BI_Invoices.Total_Cost,
BI_Invoices.Total_Sales,
CASE
WHEN BI_INVOICES.END_DEST1 '@' --<MISSING OPERATOR
THEN
BI_INVOICES.END_DEST1
WHEN BI_INV_DEST_REF_1.DEST IS NOT NULL
THEN
BI_INV_DEST_REF_1.DEST
ELSE
bi_inv_dest_ref_2.destination
END,
BI_Invoices.End_App,
BI_Invoices.Salesperson,
BI_Invoices.SOD_AUTO_KEY,
BI_Reporting_Comps.COMPCODE,
COMPANIES.COMPANY_NAME
I've marked 2 lines with MISSING OPERATOR. If you were intending for that to be Not Equal, you need to use the != rather than the "<" and ">" operator. It's a "feature" of the forum software here.
Also, what's this bit meant to do?LAST_VALUE (
CASE
WHEN BI_REPORTING_COMPS.COMPCODE IS NOT NULL
THEN
BI_REPORTING_COMPS.COMPCODE
ELSE
END
You're saying if BI_REPORTING_COMPS.COMPCODE is not null then use it otherwise use null. In oracle when you assign '' to a string it is actually set to null. With that in mind, you could just useLAST_VALUE (BI_REPORTING_COMPS.COMPCODE) -
SAS vs Oracle comparison for statistical modeling
Hi,
I am working on a project that require a lot of statistical analysis. as we are in a preliminary phase of determining which way to go, someone recommended to use SAS.
would you be able to share your experience/comments related to SAS vs Oracle comparison when it comes down to using statistical models within each of these applications. and is there a list of all statistical models that Oracle offers (it could be handy to compare it with our requirements.)
Plus, would also like to know if there is a way to test these models... just like APEX is offered free for testing purposes @ apex.oracle.com
Thanks in advanceYou don't go into much detail regarding what types of statistical technques that you might want to use. First, Oracle both partners with SAS and competes and SAS. In terms of Oracle technology for statistics and models, we ship about 50 basic statistical technques with EVERY Oracle Database for free. Those stats include below. See SQL Reference Guide for details:
Descriptive Statistics
DBMS_STAT_FUNCS: summarizes numerical columns of a table and returns count, min, max, range, mean, median, stats_mode, variance, standard deviation, quantile values, +/- n sigma values, top/bottom 5 values
Correlations
Pearson’s correlation coefficients, Spearman's and Kendall's (both nonparametric).
Cross Tabs
Enhanced with % statistics: chi squared, phi coefficient, Cramer's V, contingency coefficient, Cohen's kappa
Hypothesis Testing
Student t-test , F-test, Binomial test, Wilcoxon Signed Ranks test, Chi-square, Mann Whitney test, Kolmogorov-Smirnov test, One-way ANOVA
Distribution Fitting
Ranking functions
rank, dense_rank, cume_dist, percent_rank, ntile
Window Aggregate functions (moving & cumulative)
Avg, sum, min, max, count, variance, stddev, first_value, last_value
LAG/LEAD functions
Direct inter-row reference using offsets
Reporting Aggregate functions
Sum, avg, min, max, variance, stddev, count, ratio_to_report
Statistical Aggregates
Correlation, linear regression family, covariance
Linear regression
Fitting of an ordinary-least-squares regression line to a set of number pairs.
Frequently combined with the COVAR_POP, COVAR_SAMP, and CORR functions
Kolmogorov-Smirnov Test, Anderson-Darling Test, Chi-Squared Test, Normal, Uniform, Weibull, Exponential
Additionally, Oracle has a Database Option called Oracle Advanced Analytics which delivers 12+ hi-performance, data mining algorithms (e.g. clustering, decision trees, regression, association rules, anomaly detection, text mining, etc.) as native SQL functions that can be called from SQL, the R language or the Oracle Data Miner workflow GUI (ships with SQL Developer). There is a LOT more information on the OAA Option here http://www.oracle.com/technetwork/database/options/advanced-analytics/index.html?ssSourceSiteId=ocomen.
Hope this helps. cb -
The image above is a replica of a report that already exist. Now users want to see average Year to Day(YTD) per for each product. The idea is to aggregate the sum of each product and divide by the count of months. This report is group by month by year.
I understand using Window Function but I am running Sql Server 2008 so cannot frame. How do I go about this using SSRS?
ZionliteHi Zionlite,
Could you provide some sample data in form of a CREATE temporary table or CTE declaration?
Your example looks odd to me, als YTD Sum does not align with MTD Sums. Maybe you are calculating on a fiscal year and calculation does not start with january....but even then it's odd to me that YTD Sales Tables is 50 in January, 100 (not 50+10 = 60)
in February and dops back to 50 in March ?!
Regarding alternatives to framing via Window Functions Itzik Ben Gan suggests two alternativ methods in his book "Microsoft SQL Server 2012 HIgh-Performance T-SQL USing Window Functions".
Here an excerpt of the code provided by him. Maybe that helps already.
-- FIRST_VALUE, LAST_VALUE, NTH_VALUE
-- FIRST_VALUE, LAST_VALUE as window functions
SELECT custid, orderdate, orderid, val,
FIRST_VALUE(val) OVER(PARTITION BY custid
ORDER BY orderdate, orderid) AS val_firstorder,
LAST_VALUE(val) OVER(PARTITION BY custid
ORDER BY orderdate, orderid
ROWS BETWEEN CURRENT ROW
AND UNBOUNDED FOLLOWING) AS val_lastorder
FROM Sales.OrderValues;
custid orderdate orderid val val_firstorder val_lastorder
1 2007-08-25 10643 814.50 814.50 933.50
1 2007-10-03 10692 878.00 814.50 933.50
1 2007-10-13 10702 330.00 814.50 933.50
1 2008-01-15 10835 845.80 814.50 933.50
1 2008-03-16 10952 471.20 814.50 933.50
1 2008-04-09 11011 933.50 814.50 933.50
2 2006-09-18 10308 88.80 88.80 514.40
2 2007-08-08 10625 479.75 88.80 514.40
2 2007-11-28 10759 320.00 88.80 514.40
2 2008-03-04 10926 514.40 88.80 514.40
3 2006-11-27 10365 403.20 403.20 660.00
3 2007-04-15 10507 749.06 403.20 660.00
3 2007-05-13 10535 1940.85 403.20 660.00
3 2007-06-19 10573 2082.00 403.20 660.00
3 2007-09-22 10677 813.37 403.20 660.00
3 2007-09-25 10682 375.50 403.20 660.00
3 2008-01-28 10856 660.00 403.20 660.00
-- returning one row per customer
WITH C AS
SELECT custid,
FIRST_VALUE(val) OVER(PARTITION BY custid
ORDER BY orderdate, orderid) AS val_firstorder,
LAST_VALUE(val) OVER(PARTITION BY custid
ORDER BY orderdate, orderid
ROWS BETWEEN CURRENT ROW
AND UNBOUNDED FOLLOWING) AS val_lastorder,
ROW_NUMBER() OVER(PARTITION BY custid ORDER BY (SELECT NULL)) AS rownum
FROM Sales.OrderValues
SELECT custid, val_firstorder, val_lastorder
FROM C
WHERE rownum = 1;
custid val_firstorder val_lastorder
1 814.50 933.50
2 88.80 514.40
3 403.20 660.00
4 480.00 491.50
5 1488.80 1835.70
6 149.00 858.00
7 1176.00 730.00
8 982.00 224.00
9 88.50 792.75
10 1832.80 525.00
-- pre SQL Server 2012 solutions
-- Using row numbers
WITH OrdersRN AS
SELECT custid, val,
ROW_NUMBER() OVER(PARTITION BY custid
ORDER BY orderdate, orderid) AS rna,
ROW_NUMBER() OVER(PARTITION BY custid
ORDER BY orderdate DESC, orderid DESC) AS rnd
FROM Sales.OrderValues
SELECT custid,
MAX(CASE WHEN rna = 1 THEN val END) AS firstorderval,
MAX(CASE WHEN rnd = 1 THEN val END) AS lastorderval,
MAX(CASE WHEN rna = 3 THEN val END) AS thirdorderval
FROM OrdersRN
GROUP BY custid;
custid firstorderval lastorderval thirdorderval
1 814.50 933.50 330.00
2 88.80 514.40 320.00
3 403.20 660.00 1940.85
4 480.00 491.50 407.70
5 1488.80 1835.70 2222.40
6 149.00 858.00 330.00
7 1176.00 730.00 7390.20
8 982.00 224.00 224.00
9 88.50 792.75 1549.60
10 1832.80 525.00 966.80
-- using carry-along-sort technique
-- step 1: create concatenated strings
SELECT custid,
CONVERT(CHAR(8), orderdate, 112)
+ STR(orderid, 10)
+ STR(val, 14, 2)
COLLATE Latin1_General_BIN2 AS s
FROM Sales.OrderValues;
custid s
85 20060704 10248 440.00
79 20060705 10249 1863.40
34 20060708 10250 1552.60
84 20060708 10251 654.06
76 20060709 10252 3597.90
34 20060710 10253 1444.80
14 20060711 10254 556.62
68 20060712 10255 2490.50
88 20060715 10256 517.80
35 20060716 10257 1119.90
-- step 2: group, aggregate and extract
WITH C AS
SELECT custid,
CONVERT(CHAR(8), orderdate, 112)
+ STR(orderid, 10)
+ STR(val, 14, 2)
COLLATE Latin1_General_BIN2 AS s
FROM Sales.OrderValues
SELECT custid,
CAST(SUBSTRING(MIN(s), 19, 14) AS NUMERIC(12, 2)) AS firstorderval,
CAST(SUBSTRING(MAX(s), 19, 14) AS NUMERIC(12, 2)) AS lastorderval
FROM C
GROUP BY custid;
custid firstorderval lastorderval
1 814.50 933.50
2 88.80 514.40
3 403.20 660.00
4 480.00 491.50
5 1488.80 1835.70
6 149.00 858.00
7 1176.00 730.00
8 982.00 224.00
9 88.50 792.75
10 1832.80 525.00
-- in case ordering element supports negative values, e.g., orderid
WITH C AS
SELECT custid,
CONVERT(CHAR(8), orderdate, 112)
+ CASE SIGN(orderid) WHEN -1 THEN '0' ELSE '1' END -- negative sorts before nonnegative
+ STR(CASE SIGN(orderid)
WHEN -1 THEN 2147483648 -- if negative add abs(minnegative)
ELSE 0
END + orderid, 10)
+ STR(val, 14, 2)
COLLATE Latin1_General_BIN2 AS s
FROM Sales.OrderValues
SELECT custid,
CAST(SUBSTRING(MIN(s), 20, 14) AS NUMERIC(12, 2)) AS firstorderval,
CAST(SUBSTRING(MAX(s), 20, 14) AS NUMERIC(12, 2)) AS lastorderval
FROM C
GROUP BY custid;
Cheers
Martin -
Hi !
I have a table with session_ids, url a user visited and the time the did it.
I need output pr. session_id
Session id, durtaion of the session, the first page he visted, the last page he visited
I have tried a lot with first_value, last_value, first/last in various analytic functions, but my head cant seem to find the correct solution.
(aprt from coding it in PL/SQL)
This is an example of my table:
drop table mette_interval;
create table mette_interval (session_i number, url varchar2(400), url_time date);
insert into mette_interval values (1, 'start page', sysdate);
insert into mette_interval values (1, 'xxxxside z', sysdate+interval '5' second);
insert into mette_interval values (1, 'end pagexxxxxside z', sysdate+interval '6' second);
insert into mette_interval values (2, 'page xxx z',sysdate+interval '0' second);
insert into mette_interval values (2, 'page yyyy z', sysdate+interval '10' second);
insert into mette_interval values (3, 'page whatever z', sysdate+interval '1' second);
select session_i, (max(url_time)-min(url_time))*24*60*60 duration
from mette_interval
group by session_i;
Can you give me a hint?
Regards
MetteSQL> select * from mette_interval;
SESSION_I URL URL_TIME
1 start page 24-MAR-09
1 xxxxside z 24-MAR-09
1 end pagexxxxxside z 24-MAR-09
2 page xxx z 24-MAR-09
2 page yyyy z 24-MAR-09
3 page whatever z 24-MAR-09
6 rows selected.
SQL> select session_i,(max(url_time)-min(url_time))*24*60*60 duration,
2 max(url) keep(dense_rank first order by url_time) frst,
3 max(url) keep(dense_rank last order by url_time) lst
4 from mette_interval
5 group by session_i;
SESSION_I DURATION FRST LST
1 6 start page end pagexxxxxside z
2 10 page xxx z page yyyy z
3 0 page whatever z page whatever zToo Late...
Edited by: jeneesh on Mar 24, 2009 12:38 PM -
Replacing Oracle's FIRST_VALUE and LAST_VALUE analytical functions.
Hi,
I am using OBI 10.1.3.2.1 where, I guess, EVALUATE is not available. I would like to know alternatives, esp. to replace Oracle's FIRST_VALUE and LAST_VALUE analytical functions.
I want to track some changes. For example, there are four methods of travel - Air, Train, Road and Sea. Would like to know traveler's first method of traveling and the last method of traveling in an year. If both of them match then a certain action is taken. If they do not match, then another action is taken.
I tried as under.
1. Get Sequence ID for each travel within an year per traveler as Sequence_Id.
2. Get the Lowest Sequence ID (which should be 1) for travels within an year per traveler as Sequence_LId.
3. Get the Highest Sequence ID (which could be 1 or greater than 1) for travels within an year per traveler as Sequence_HId.
4. If Sequence ID = Lowest Sequence ID then display the method of travel as First Method of Travel.
5. If Sequence ID = Highest Sequence ID then display the method of travel as Latest Method of Travel.
6. If First Method of Travel = Latest Method of Travel then display Yes/No as Match.
The issue is cells could be blank in First Method of Travel and Last Method of Travel unless the traveler traveled only once in an year.
Using Oracle's FIRST_VALUE and LAST_VALUE analytical functions, I can get a result like
Traveler | Card Issue Date | Journey Date | Method | First Method of Travel | Last Method of Travel | Match?
ABC | 01/01/2000 | 04/04/2000 | Road | Road | Air | No
ABC | 01/01/2000 | 15/12/2000 | Air | Road | Air | No
XYZ | 01/01/2000 | 04/05/2000 | Train | Train | Train | Yes
XYZ | 01/01/2000 | 04/11/2000 | Train | Train | Train | Yes
Using OBI Answers, I am getting something like this.
Traveler | Card Issue Date | Journey Date | Method | First Method of Travel | Last Method of Travel | Match?
ABC | 01/01/2000 | 04/04/2000 | Road | Road | <BLANK> | No
ABC | 01/01/2000 | 15/12/2000 | Air | <BLANK> | Air | No
XYZ | 01/01/2000 | 04/05/2000 | Train | Train | <BLANK> | No
XYZ | 01/01/2000 | 04/11/2000 | Train | <BLANK> | Train | No
Above, for XYZ traveler the Match? clearly shows a wrong result (although somehow it's correct for traveler ABC).
Would appreciate if someone can guide me how to resolve the issue.
Many thanks,
Manoj.
Edited by: mandix on 27-Nov-2009 08:43
Edited by: mandix on 27-Nov-2009 08:47Hi,
Just to recap, in OBI 10.1.3.2.1, I am trying to find an alternative way to FIRST_VALUE and LAST_VALUE analytical functions used in Oracle. Somehow, I feel it's achievable. I would like to know answers to the following questions.
1. Is there any way of referring to a cell value and displaying it in other cells for a reference value?
For example, can I display the First Method of Travel for traveler 'ABC' and 'XYZ' for all the rows returned in the same column, respectively?
2. I tried RMIN, RMAX functions in the RDP but it does not accept "BY" clause (for example, RMIN(Transaction_Id BY Traveler) to define Lowest Sequence Id per traveler). Am I doing something wrong here? Why can a formula with "BY" clause be defined in Answers but not the RPD? The idea is to use this in Answers. This is in relation to my first question.
Could someone please let me know?
I understand that this thread that I have posted is related to something that can be done outside OBI, but still would like to know.
If anything is not clear please let me know.
Thanks,
Manoj. -
Use of FIRST_VALUE OVER in a PL/SQL query
Hello,
Here is my problem:
I'm trying to execute a query using FIRST_VALUE OVER in a PL/SQL procedure, e.g.
SELECT FIRST_VALUE (name) OVER (order by birthdate)
FROM birthday_table
WHERE location = 'HOME';
I need to get the value returned. I tried to do it using an INTO clause and
also with EXECUTE IMMEDIATE, but I get an error like "invalid column name".
Thank you,
Olivier.Assuming the query runs successfully outside of PL/SQL, the execute immediate construct would be:
execute immediate 'select first_value ... where location = :loc' into v_some_variable using 'HOME'; -
How to get LAST_VALUE from an Analytic Function within a report?
My analytical report has following sql:
SELECT....
DENSE_RANK() OVER (PARTITION BY pco.appropriation ORDER BY pco.appropriation,
pco.fiscal_year ASC NULLS LAST) "Duration Years",
SUM(pco.quantity) OVER (PARTITION BY sms.data_source ORDER BY
sms.data_source, cst.display_nm RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT
ROW) "Quantity Cum",
FROM ........
I have a request to calculate the percentage value by dividing MAX or LASTVALUE of these two functions at current row level:_
%DENSE_RANK = LAST_VALUE of ? DENSE_RANK() OVER (PARTITION BY pco.appropriation ORDER BY pco.appropriation,
pco.fiscal_year ASC NULLS LAST) "Duration Years"
/ (divide by)
DENSE_RANK() OVER (PARTITION BY pco.appropriation ORDER BY pco.appropriation,
pco.fiscal_year ASC NULLS LAST) "Duration Years"
%SUM = LAST_VALUE of ? SUM(pco.quantity) OVER (PARTITION BY sms.data_source ORDER BY
sms.data_source, cst.display_nm RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT
ROW) "Quantity Cum",
/ (divide by)
SUM(pco.quantity) OVER (PARTITION BY sms.data_source ORDER BY
sms.data_source, cst.display_nm RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT
ROW) "Quantity Cum"
Example of report output:
DENSE RANK DENSE RANK % SUM SUM %
1 10% 10 10%
2 20% 20 20%
3 100% 30 100%
1 10% 10 10%
2 20% 20 20%
I appreciate your help to implement LAST_VALUE function for this case. Many thanks in advance.
Rob.
Edited by: user10455955 on Dec 17, 2008 9:25 AMHi Rod,
Thank you for replying. My intentions are:
1. to get last value of DENSE_RANK(), and divide by fisrt until last DENSE_RANK() value within defined partition.
Example: I have DENSE_RANK() from 1 to 7, and want to divide last value (7) by 1, 2,... so on until 7, so last value 7 always renders 100%
2. to get last value of cumulative total, and divide fisrt until and last cumulative total value within defined partition
Example: I have 3 values 1, 2, 3. Fisrt cumulative total is 1 , second cumulative is 3 (1+2) , third cumulative is 6 (1+2+3). I want to divide last cumulative total 6 by 1, then 2, then 3.
Thanks again.
Rob.
Edited by: user10455955 on Dec 22, 2008 9:16 AM
Edited by: user10455955 on Dec 22, 2008 9:18 AM -
Hi,
I am problem pulling right set of data for the below situation.
SELECT
FIRST_VALUE(p1)
OVER (PARTITION BY workorderid ORDER BY NVL(completeddate,createdate) DESC NULLS LAST) pressure
FROM HISTORY
Lets say that result set has values for p1 as no and yes for the same completeddate, then the
query returns value 'no' because it sorts the data alphabetically.
all i what is, when the completed date is same for two records then look up create date and give me the value of p1 based on max(create date).
How do i do that using analytical function?
Thanks
BilluSorry, i wasn't clear enough earlier.
here is my entire query posted :
SELECT
m.loannumber,
w.ordernumber,
o.spikey clientcode,
v.id vendorname,
w.spiworkcode workcode,
w.department_fk department,
SUBSTR(w.loantypetermid, 10) loantype,
TRUNC(w.orderdate) orderdate,
vw_rhist.wcompleteddate Winterization_Completed_Date,
CASE WHEN vw_rhist.wintsystemtype = 'HeatingSystemType.Dry'
THEN 'Dry'
WHEN vw_rhist.wintsystemtype = 'HeatingSystemType.Steam'
THEN 'Steam'
WHEN vw_rhist.wintsystemtype = 'HeatingSystemType.Radiant'
THEN 'Radiant'
ELSE NULL
END System_Type,
CASE WHEN vw_rhist.pressuretestsystem = 'YesNo.Yes' THEN 'Yes'
WHEN vw_rhist.pressuretestsystem = 'YesNo.No' THEN 'No'
ELSE NULL
END pressuretestsystem,
CASE WHEN vw_rhist.holdpressure = 'YesNo.Yes' THEN 'Yes'
WHEN vw_rhist.holdpressure = 'YesNo.No' THEN 'No'
ELSE NULL
END holdpressure,
CASE WHEN vw_rhist.systemwell = 'YesNo.Yes' THEN 'Yes'
WHEN vw_rhist.systemwell = 'YesNo.No' THEN 'No'
ELSE NULL
END systemwell,
a.state state
FROM organizationalrole o,
vendor v,
serviceableasset s,
address a,
mortgage m,
(SELECT *
FROM workorder
WHERE department_fk = 2
AND loantypetermid IN ( 'LoanType.CDG','LoanType.CV','LoanType.FHA','LoanType.FMC','LoanType.FNM',
'LoanType.REO','LoanType.UNK','LoanType.VA'))w,
SELECT workorderid,rnk,wcompleteddate,pressuretestsystem,
holdpressure,systemwell,wintsystemtype
FROM
((SELECT workorderid,
RANK() OVER (PARTITION BY workorderid ORDER BY oid) rnk,
MIN(COALESCE(winterizationdate, completeddate, createdate))
OVER (PARTITION BY workorderid) wcompleteddate,
FIRST_VALUE(pressuretestsystem)
OVER (PARTITION BY workorderid
ORDER BY NVL(completeddate, createdate) DESC NULLS LAST)
pressuretestsystem, FIRST_VALUE(holdpressure)
OVER (PARTITION BY workorderid
ORDER BY NVL(completeddate, createdate) DESC NULLS LAST)
holdpressure,
FIRST_VALUE(systemwell)
OVER (PARTITION BY workorderid
ORDER BY NVL(completeddate, createdate) DESC NULLS LAST)
systemwell,
FIRST_VALUE(wintsystemtype)
OVER (PARTITION BY workorderid
ORDER BY NVL(completeddate, createdate) DESC NULLS LAST)
wintsystemtype
FROM vwresulthistory
WHERE resulttype = 'OrderUpdate'
AND iswinterized = 'WinterizationCompleted.Yes') vw_rhist1)
WHERE wCompleteddate >=
TO_DATE('10/01/2009','MM/DD/YYYY') AND
wCompleteddate <= TO_DATE('10/6/2009','MM/DD/YYYY')) vw_rhist
WHERE vw_rhist.rnk = 1
AND v.objectid = w.vendor_fk
AND w.ordernumber = vw_rhist.workorderid
AND w.servicingasset_fk = s.objectid
AND s.address_fk = a.objectid
AND o.objectid = w.client_fk
AND m.objectid = s.primaryloan_fk
ORDER BY 2
The problem i have is with the first_value that is in bold. Sometimes I do have two identical completeddate, in that situation, the first_value returns pressuretestsystem sorted aphabetically, say you have two identical completed dates of 12/3/09 and pressuretestsystem values of 'no' and 'yes'. What I get is 'no'.
In that kind of situations, i want to look up create date and return the latest value (which here is 'yes'). Do i need case statement here?
Thanks for reading this far.
Billu. -
EVALUATE in OBIEE with Analytic function LAST_VALUE
Hi,
I'm trying to use EVALUATE with analytic function LAST_VALUE but it is giving me error below:
[nQSError: 17001] Oracle Error code: 30483, message: ORA-30483: window functions are not allowed here at OCI call OCIStmtExecute. [nQSError: 17010] SQL statement preparation failed. (HY000)
Thanks
Kumar.Hi Kumar,
The ORA error tells me that this is something conveyed by the oracle database but not the BI Server. In this case, the BI server might have fired the incorrect query onto the DB and you might want to check what's wrong with it too.
The LAST_VALUE is an analytic function which works over a set/partition of records. Request you to refer to the semantics at http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions073.htm and see if it is violating any rules here. You may want to post the physical sql here too to check.
Hope this helps.
Thank you,
Dhar -
First_value in Oracle olap based on non - time dimension
Hi Experts,
I am trying to figure out to do first_value kind of calculation in Oracle OLAP.
Here is the requirement -
Fact table -
cust_id valid_flag balance
1 y 1000
1 y 1500
2 N 0
2 y 2000
2 y 2500
If valid_flag ='N' and balance =0, then set balance =0 for other cells for the customer. This needs to be done for all the dimensions.
Any pointer would be useful.
Regards, NeeleshIf the switch is really based on a dimension attribute (named particular_value), then it should be easy to create a derived measure.
CASE
WHEN particular_dim.particular_value = 'N'
THEN 0
ELSE my_cube.balance
ENDBut perhaps what you mean is that there is another measure, IS_VALID say, and you need to get the value of IS_VALID for the current cust_id and the member named 'particular_value' of the particular_dim. In this case it would look something like this.
CASE
WHEN my_cube.is_valid[particular_dim = 'particular_value'] = 'N'
THEN 0
ELSE my_cube.balance
ENDI expect that neither of the above expressions is right, but it should give you some pointers as to the kinds of tricks you can use. -
Peformance of First_Value
Hi ,
I want to know which of the two queries is better in terms of performance(using first_value or a sub query).
Let us assume that salary is unique...
1) select first_value(ename ) over (order by sal) from emp;
or
2) select ename from emp where sal = (select min(sal) from emp )
Thanks,
AnandYou are comparing apple with oranges. It is because you are comparing analytical vs aggregate. They are different. Because
SQL> select first_value(ename ) over (order by sal) from emp;
FIRST_VALU
SMITH
SMITH
SMITH
SMITH
SMITH
SMITH
SMITH
SMITH
SMITH
SMITH
SMITH
FIRST_VALU
SMITH
SMITH
SMITH
SMITH
15 rows selected.
SQL> select ename from emp where sal = (select min(sal) from emp);
ENAME
SMITHFor more information check this url.
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:74525921631614
Regards
Raj -
Hi Guys,
How to modify LAST_VALUE call in query
select t.*, last_value( order_val) over(order by order_date) from testx t
to get 12 for dates 7/1/2010, 8/1/2010, 9/1/2010
ID ORDER_DATE ORDER_VAL LAST_VALUE(ORDER_VAL)OVER(ORDE
1 1/1/2010 3 3
2 2/1/2010 5 5
3 3/1/2010 7 7
4 4/1/2010 8 8
5 5/1/2010 9 9
6 6/1/2010 12 12
7 7/1/2010 12
8 8/1/2010 12
9 9/1/2010 12
(Ora 9.2):
create table testx ( id number, order_date date, order_val number );
insert into testx values ( 1, to_date('2010-01-01','yyyy-mm-dd'), 3 );
insert into testx values ( 2, to_date('2010-02-01','yyyy-mm-dd'), 5 );
insert into testx values ( 3, to_date('2010-03-01','yyyy-mm-dd'), 7 );
insert into testx values ( 4, to_date('2010-04-01','yyyy-mm-dd'), 8 );
insert into testx values ( 5, to_date('2010-05-01','yyyy-mm-dd'), 9 );
insert into testx values ( 6, to_date('2010-06-01','yyyy-mm-dd'), 12 );
insert into testx values ( 7, to_date('2010-07-01','yyyy-mm-dd'), null );
insert into testx values ( 8, to_date('2010-08-01','yyyy-mm-dd'), null );
insert into testx values ( 9, to_date('2010-09-01','yyyy-mm-dd'), null );
Thanks,
Regards,
PiotrThanks for pointing that Alex.
Not sure if @OP is looking at repeating the Maximum order_value for NULL records or the last value. In case if it hae to be the maximum order_Val, then here it is:
SQL> ed
Wrote file afiedt.buf
1 select id
2 , order_date
3 , order_val
4 , max (order_val) over (partition by grp)
5 from (
6 select id
7 , order_date
8 , order_val
9 , sum (nvl2 (order_val, 1, 0)) over (order by order_val) grp
10* from testx)
SQL> /
ID ORDER_DAT ORDER_VAL MAX(ORDER_VAL)OVER(PARTITIONBYGRP)
1 01-JAN-10 3 3
2 01-FEB-10 5 5
3 01-MAR-10 7 7
4 01-APR-10 8 8
6 01-JUN-10 12 12
5 01-MAY-10 15 15
7 01-JUL-10 15
8 01-AUG-10 15
9 01-SEP-10 15
9 rows selected.
SQL> Edited by: AP on Aug 11, 2010 2:30 AM -
When to use First instead of First_Value functions
When would you use the First_Values function instead of First? What's the difference between the two?
Here are some examples of both in action. Use the analytic function FIRST_VALUE when you don't want to group your records. Use the aggregate function FIRST when you do.
select
deptno ,
hiredate ,
ename ,
first_value( ename ) over ( partition by deptno order by hiredate ) first_hired
from emp
order by deptno, hiredate ;
DEPTNO HIREDATE ENAME FIRST_HIRE
10 1981-06-09 CLARK CLARK
10 1981-11-17 KING CLARK
10 1982-01-23 MILLER CLARK
20 1980-12-17 SMITH SMITH
20 1981-04-02 JONES SMITH
20 1981-12-03 FORD SMITH
20 1987-04-19 SCOTT SMITH
20 1987-05-23 ADAMS SMITH
30 1981-02-20 ALLEN ALLEN
30 1981-02-22 WARD ALLEN
30 1981-05-01 BLAKE ALLEN
30 1981-09-08 TURNER ALLEN
30 1981-09-28 MARTIN ALLEN
30 1981-12-03 JAMES ALLEN
14 rows selected.
select
deptno,
min(ename) keep ( dense_rank first order by hiredate ) as first_hired
from emp
group by deptno
order by deptno ;
DEPTNO FIRST_HIRE
10 CLARK
20 SMITH
30 ALLEN
3 rows selected.As far as analytic FIRST_VALUE versus the analytic version of FIRST, FIRST_VALUE has the option to IGNORE NULLS whereas FIRST doesn't.
select
deptno ,
hiredate ,
comm ,
first_value( comm IGNORE NULLS ) over ( partition by deptno order by hiredate desc )
as first_value ,
min(comm) keep ( dense_rank first order by hiredate desc )
over ( partition by deptno )
as first
from emp
order by deptno, hiredate ;
DEPTNO HIREDATE COMM FIRST_VALUE FIRST
10 1981-06-09
10 1981-11-17
10 1982-01-23
20 1980-12-17
20 1981-04-02
20 1981-12-03
20 1987-04-19
20 1987-05-23
30 1981-02-20 300 1400
30 1981-02-22 500 1400
30 1981-05-01 1400
30 1981-09-08 0 1400
30 1981-09-28 1400 1400
30 1981-12-03
14 rows selected.Other than that the two seem functionally equivalent. I prefer FIRST_VALUE over FIRST though because its syntax is more familiar.
Joe Fuda
SQL Snippets
Message was edited by: SnippetyJoe - added third example -
Can anyone tell me if there is a more efficient way to do the following........
SELECT distinct accprf.account_id
first_value(accprf.value_start)
over (partition by accprf.account_id order by accprf.start_date) ,
first_value(accprf.value_end)
over (partition by accprf.account_id order by accprf.end_date desc)
FROM account_performance accprf
The table account_performance has more than one row per account_id. Each row has a start date and end date, with account performance information for that time interval. The above gets the values from the very first entry and the very last entry per account_id.
I was expecting to find a less complicated way to do the above.
Thanks, Mario.Well, in that case it doesn't matter!
This is a little demonstration:
SQL> drop table t;
Table dropped.
SQL>
SQL> create table t (c1 number, c2 number, c3 number);
Table created.
SQL>
SQL> insert into t values (1, 1, 10);
1 row created.
SQL> insert into t values (1, 2, 11);
1 row created.
SQL> insert into t values (1, 3, 7);
1 row created.
SQL>
SQL>
SQL> insert into t values (2, 3, 20);
1 row created.
SQL> insert into t values (2, 4, 21);
1 row created.
SQL> insert into t values (2, 5, 15);
1 row created.
SQL>
SQL> SELECT c1,
2 SUM(c3) keep (dense_rank first order by c2) sum,
3 MIN(c3) keep (dense_rank first order by c2) min,
4 MAX(c3) keep (dense_rank first order by c2) max
5 FROM t
6 group by c1;
C1 SUM MIN MAX
1 10 10 10
2 20 20 20Message was edited by:
Michel
Sorry,
It have made an implicit assumption that c2 was unique or it is not true and then you are right. It must be min and not max to meet the first query.
Thanks for your correction.
Maybe you are looking for
-
I am facing the same disaster ,, I am forced to reactivate / reinstall CS 5 and after 10 hours of trying all options fail . WHy cant I simply reenter my serial number , rather than spead hours on uninstalling then trying to reinstall an 8 hou
-
I was wondering if their is a way to export or import an address book into webmail (squirrelmail 1.4.5) that is built into 10.4.8. I know that you can add people to your address book through webmail directly and I don't see any options to either impo
-
Hi, Sorry if this is a really silly question, I just need some clarification. I'm carrying out a project to migrate users/groups and everything else 'AD' from 1 forest into a target forest. There's a 2 way trust in place and I will be starting ADMT
-
Strange Facetime activation error
I have followed with interest the issues surrounding Facetime activation problems. I have one I have not yet seen. My new IPOD Touch G4 will not activate facetime. I get the most unusual error message: unable to verify email because it is already in
-
No Missed Calls AirPlane Mode Bug
When I put my iPhone in AirPlane I don't recive calls or iMessages. (Normal) When I disable AirPlane mode, any calls that I recived while AirPlane mode was on don't appear at all. So it shows no missed calls, but Messages do show up. I have tested th