SlideShare a Scribd company logo
1 of 83
The Model Clause
Spreadsheet Techniques
using SQL
Scott Wesley
Agenda
• Concepts
• Cell Referencing
• Focus
• Performance
• Final thoughts…
Any Model experts?
SELECT c, p, m, pp, ip
FROM mortgage
MODEL
REFERENCE R ON
(SELECT customer, fact, amt
FROM mortgage_facts
MODEL DIMENSION BY (customer, fact)
MEASURES (amount amt) RULES
(amt[any, 'PaymentAmt']= (amt[CV(),'Loan']*
Power(1+ (amt[CV(),'Annual_Interest']/100/12),amt[CV(),'Payments'])*
(amt[CV(),'Annual_Interest']/100/12)) /
(Power(1+(amt[CV(),'Annual_Interest']/100/12), amt[CV(),'Payments'])
- 1)))
DIMENSION BY (customer cust, fact)
MEASURES (amt)
MAIN amortization
PARTITION BY (customer c)
DIMENSION BY (0 p)
MEASURES (principalp pp, interestp ip, mort_balance m, customer mc)
RULES ITERATE(1000) UNTIL (ITERATION_NUMBER+1 =r.amt[mc[0],'Payments'])
(ip[ITERATION_NUMBER+1] = m[CV()-1] * r.amt[mc[0],
'Annual_Interest']/1200
,pp[ITERATION_NUMBER+1] = r.amt[mc[0], 'PaymentAmt'] - ip[CV()]
,m[ITERATION_NUMBER+1] = m[CV()-1] - pp[CV()])
ORDER BY c, p;
FizzBuzz
• Write a program that prints the numbers
from 1 to 100.
• But for multiples of three print “Fizz”
instead of the number and for the
multiples of five print “Buzz”.
• For numbers which are multiples of both
three and five print “FizzBuzz”
http://tkyte.blogspot.com/2007/02/what-is-your-fizzbuzz-factor.html
SQL> WITH data AS (SELECT LEVEL AS n
FROM DUAL CONNECT BY LEVEL <= 100)
SELECT n, NVL(CASE WHEN MOD(n,3) = 0 THEN 'Fizz' END ||
CASE WHEN MOD(n,5) = 0 THEN 'Buzz' END,
TO_CHAR(n)) AS answer
FROM data;
N ANSWER
---- -----------
1 1
2 2
3 Fizz
4 4
5 Buzz
6 Fizz
7 7
8 8
9 Fizz
10 Buzz
11 11
12 Fizz
13 13
14 14
15 FizzBuzz
16 16
17 17
18 Fizz
...
Anthony Wilson said....
So... do we win points by using MODEL, or get thrown out of the interview on
mental health grounds?
Nobody in their right mind actually uses this stuff, right?
:)
select id, n
from all_objects
where object_id = 1
model
dimension by (object_id id)
measures (object_name n)
rules (
n[for id from 1 to 100 increment 1] = to_char(cv(id)),
n[mod(id, 3) = 0] = 'fizz',
n[mod(id, 5) = 0] = 'buzz',
n[mod(id, 15) = 0] = 'fizzbuzz'
)
order by id
SQL Spreadsheets
Craft
Basic Syntax
<prior clauses of SELECT statements>
MODEL [main] [RETURN {ALL|UPDATED} ROWS]
[reference models]
[PARTITION BY (<cols>)]
DIMENSION BY (<cols>)
MEASURES (<cols>)
[IGNORE NAV] | [KEEP NAV]
[RULES
[UPSERT | UPDATE]
[AUTOMATIC ORDER | SEQUENTIAL ORDER]
[ITERATE (n) [UNTIL <condition>] ]
( <cell_assignment> = <expression> ... )
SELECT country
,year
,sales
,previous_year
,before_that
FROM sales_view
GROUP BY year, country
-- Define model structure/options
MODEL RETURN ALL ROWS
PARTITION BY (country)
DIMENSION BY (year)
MEASURES (SUM(sales) AS sales
-- Define 'calculated columns'
,CAST(NULL AS NUMBER) previous_year
,CAST(NULL AS NUMBER) before_that)
-- Define rule options
RULES AUTOMATIC ORDER (
-- Define actual rules
previous_year[ANY] = sales[CV()-1]
,before_that [ANY] = sales[CV()-2]
)
-- Define order of entire result set
ORDER BY country, year;
Apply model
clause to
this query
Concepts
Country Product Year Sales
Partition Dimension Dimension Measure
AUS HAMMER 2006 10
AUS NAIL 2006 200
NZ NAIL 2006 300
NZ DRILL 2007 50
Dimension
Country Product Year Sales
Partition Dimension Dimension Measure
<prior clauses of SELECT statements>
MODEL [main] [RETURN {ALL|UPDATED} ROWS]
[reference models]
[PARTITION BY (<cols>)]
DIMENSION BY (product p, year y)
MEASURES (<cols>)
[IGNORE NAV] | [KEEP NAV]
[RULES …
Measure
Country Product Year Sales
Partition Dimension Dimension Measure
<prior clauses of SELECT statements>
MODEL [main] [RETURN {ALL|UPDATED} ROWS]
[reference models]
[PARTITION BY (<cols>)]
DIMENSION BY (<cols>)
MEASURES (sales)
[IGNORE NAV] | [KEEP NAV]
[RULES …
Partition
Country Product Year Sales
Partition Dimension Dimension Measure
<prior clauses of SELECT statements>
MODEL [main] [RETURN {ALL|UPDATED} ROWS]
[reference models]
[PARTITION BY (country)]
DIMENSION BY (<cols>)
MEASURES (<cols>)
[IGNORE NAV] | [KEEP NAV]
[RULES …
Array
20
15 5
35 15
Hammer Drill
Product
2006
2007
2008
C
ountry
Year
Aus
N
Z
Rules
<prior clauses of SELECT statements>
MODEL [main] [RETURN {ALL|UPDATED} ROWS]
[reference models]
[PARTITION BY (<cols>)]
DIMENSION BY (<cols>)
MEASURES (<cols>)
[IGNORE NAV] | [KEEP NAV]
[RULES
[UPSERT | UPDATE]
[AUTOMATIC ORDER | SEQUENTIAL ORDER]
[ITERATE (n) [UNTIL <condition>] ]
( <cell_assignment> = <expression> ... )
Rules
COUNTRY PRODUCT YEAR SALES
Partition Dimension Dimension Measure
AUS Hammer 2006 20
AUS Hammer 2007 15
AUS Drill 2007 5
NZ Hammer 2006 15
NZ Hammer 2007 10
NZ Drill 2007 10
AUS Hammer 2008 35
AUS Drill 2008 15
NZ Hammer 2008 25
NZ Drill 2008 30
Original
Data
Rule
Results
Sales[Hammer,2008] = Sales[Hammer,2006]+Sales[Hammer,2007]
Sales[Drill ,2008] = Sales[Drill,2007]*3
Spreadsheet
Sales[Hammer,2008] = Sales[Hammer,2006]+Sales[Hammer,2007]
Sales[Drill ,2008] = Sales[Drill,2007]*3
Return Rows
<prior clauses of SELECT statements>
MODEL [main] [RETURN {ALL|UPDATED} ROWS]
[reference models]
[PARTITION BY (<cols>)]
DIMENSION BY (<cols>)
MEASURES (<cols>)
[IGNORE NAV] | [KEEP NAV]
[RULES
[UPSERT | UPDATE]
[AUTOMATIC ORDER | SEQUENTIAL ORDER]
[ITERATE (n) [UNTIL <condition>] ]
( <cell_assignment> = <expression> ... )
Rules
COUNTRY PRODUCT YEAR SALES
Partition Dimension Dimension Measure
AUS Hammer 2006 20
AUS Hammer 2007 15
AUS Drill 2007 5
NZ Hammer 2006 15
NZ Hammer 2007 10
NZ Drill 2007 10
AUS Hammer 2008 35
AUS Drill 2008 15
NZ Hammer 2008 25
NZ Drill 2008 30
RETURN
ALL
ROWS
RETURN
UPDATED
ROWS
Sales[Hammer,2008] = Sales[Hammer,2006]+Sales[Hammer,2007]
Sales[Drill ,2008] = Sales[Drill,2007]*3
Positional Cell Referencing
SELECT country, product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES (
sales['Bounce', 2000] = 10
,sales['Bounce', 2008] = 20 );
COUNTRY PROD YEAR SALES
------------ ------------ ----- ----------
Australia Bounce 2000 10
Australia Bounce 2008 20
Symbolic Cell Referencing
SELECT country, product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES (
sales[prod = 'Bounce', year > 1999] = 10 )
ORDER BY country, product, year;
COUNTRY PRODUCT YEAR SALES
------------ ------------ ----- ----------
Australia Bounce 2000 10
Australia Bounce 2001 10
Multi-Cell Access on Right Side
SELECT country, product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES (
sales['Bounce',2008] = 100 + MAX(sales)
['Bounce', year BETWEEN 1998 and 2002]
,sales['Y Box',2008] = 1.3 * PERCENTILE_DISC(0.5)
WITHIN GROUP (ORDER BY sales)
[product in ('Bounce', 'Y Box'), year < 2003]);
COUNTRY PRODUCT YEAR SALES
---------- -------- ----- -------
Australia Bounce 2008 3861
Australia Y Box 2008 4889
Multi-Cell Access on Right Side
SELECT country, product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES (
sales['Bounce',2008] = 100 + MAX(sales)
['Bounce', year BETWEEN 1998 and 2002]
,sales['Y Box',2008] = 1.3 * PERCENTILE_DISC(0.5)
WITHIN GROUP (ORDER BY sales)
[product in ('Bounce', 'Y Box'), year < 2003]);
COUNTRY PRODUCT YEAR SALES
---------- -------- ----- -------
Australia Bounce 2008 3861
Australia Y Box 2008 4889
CV()
SELECT country, product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES (
sales['Bounce', year BETWEEN 1995 AND 2002] =
sales['Mouse Pad', CV(year)] +
0.2 * sales['Y Box', CV()]);
COUNTRY PRODUCT YEAR SALES
---------- -------- ----- -------
Australia Bounce 1999 6061
Australia Bounce 2000 8154
Australia Bounce 2001 15211
SELECT country, product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES (
sales['Bounce', year BETWEEN 1995 AND 2002] =
sales['Mouse Pad', CV(year)] +
0.2 * sales['Y Box', CV()]);
COUNTRY PRODUCT YEAR SALES
---------- -------- ----- -------
Australia Bounce 1999 6061
Australia Bounce 2000 8154
Australia Bounce 2001 15211
SELECT country, product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES (
sales['Bounce', year BETWEEN 1995 AND 2002] =
sales['Mouse Pad', CV(year)] +
0.2 * sales['Y Box', CV()]);
COUNTRY PRODUCT YEAR SALES
---------- -------- ----- -------
Australia Bounce 1999 6061
Australia Bounce 2000 8154
Australia Bounce 2001 15211
SELECT country, product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES (
sales['Bounce', 1999] =
sales['Mouse Pad',1999]+0.2*sales['Y Box',1999]
sales['Bounce', 2000] =
sales['Mouse Pad',2000]+0.2*sales['Y Box',2000]
sales['Bounce', 20001] =
sales['Mouse Pad',2001]+0.2*sales['Y Box',2001]);
CV(year)-1
SELECT country, product, year, sales, p_year, growth_pct
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales, 0 p_year, 0 growth_pct)
RULES (
p_year[product IN ('Bounce','Y Box'), year BETWEEN 1998 and 2001]
= sales[CV(product), CV(year) -1]
,growth_pct[product IN ('Bounce','Y Box'), year BETWEEN 1998 and
2001]
= 100* (sales[CV(product), CV(year)] -
sales[CV(product), CV(year) -1] ) /
sales[CV(product), CV(year) -1])
ORDER BY country, product, year;
COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT
---------- --------- ----- ------- ------- ----------
Australia Bounce 1999 1878
Australia Bounce 2000 3151 1878 67.83
Australia Bounce 2001 3761 3151 19.33
Australia Y Box 1999 13773
Australia Y Box 2000 27007 13773 96.09
Australia Y Box 2001 59291 27007 119.54
SELECT country, product, year, sales, p_year, growth_pct
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales, 0 p_year, 0 growth_pct)
RULES (
p_year[product IN ('Bounce','Y Box'), year BETWEEN 1998 and 2001]
= sales[CV(product), CV(year) -1]
,growth_pct[product IN ('Bounce','Y Box'), year BETWEEN 1998 and
2001]
= 100* (sales[CV(product), CV(year)] -
sales[CV(product), CV(year) -1] ) /
sales[CV(product), CV(year) -1])
ORDER BY country, product, year;
COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT
---------- --------- ----- ------- ------- ----------
Australia Bounce 1999 1878
Australia Bounce 2000 3151 1878 67.83
Australia Bounce 2001 3761 3151 19.33
Australia Y Box 1999 13773
Australia Y Box 2000 27007 13773 96.09
Australia Y Box 2001 59291 27007 119.54
SELECT country, product, year, sales, p_year, growth_pct
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales, 0 p_year, 0 growth_pct)
RULES (
p_year[product IN ('Bounce','Y Box'), ANY]
= sales[CV(product), CV(year) -1]
,growth_pct[product IN ('Bounce','Y Box'), year IS ANY]
= 100* (sales[CV(product), CV(year)] -
sales[CV(product), CV(year) -1] ) /
sales[CV(product), CV(year) -1])
ORDER BY country, product, year;
COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT
---------- --------- ----- ------- ------- ----------
Australia Bounce 1999 1878
Australia Bounce 2000 3151 1878 67.83
Australia Bounce 2001 3761 3151 19.33
Australia Y Box 1999 13773
Australia Y Box 2000 27007 13773 96.09
Australia Y Box 2001 59291 27007 119.54
Analytics vs Model
LAG(sales,1) OVER
(PARTITION BY prod
ORDER BY year) p_year
p_year[prod IS ANY, year IS ANY]
= sales[CV(prod), CV(year)-1]
SAME!
Or is it…?
Model method:
COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT
---------- --------- ----- ------------ ------- ----------
Australia Bounce 1999 1,878
Australia Bounce 2000 3,151 1878 67.83
Australia Bounce 2001 3,761 3151 19.33
Australia Bounce 2003 8,790
Analytic method:
COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT
---------- --------- ----- ------------ ------- ----------
Australia Bounce 1999 1,878
Australia Bounce 2000 3,151 1878 67.83
Australia Bounce 2001 3,761 3151 19.33
Australia Bounce 2003 8,790 3761 133.73
Rule Repetition
SELECT product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
DIMENSION BY (product, year)
MEASURES (sales)
RULES UPSERT (
sales['Mouse Pad', 2008] = 1.3 * sales['Mouse Pad', 2001]
,sales['Bounce', 2008] = 1.3 * sales['Bounce', 2001]
,sales['Y Box', 2008] = 1.3 * sales['Y Box', 2001]
);
PRODUCT YEAR SALES
---------- ----- -------
Y Box 2008 77078
Bounce 2008 4888
Mouse Pad 2008 4358
3 rows selected.
Symbolic Reference
SELECT product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
DIMENSION BY (product, year)
MEASURES (sales)
RULES UPSERT (
sales[product IN ('Mouse Pad', 'Bounce', 'Y Box')
,2008] = 1.3 * sales[CV(product), 2001] );
no rows selected
Positional Reference
SELECT product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
DIMENSION BY (product, year)
MEASURES (sales)
RULES UPSERT (
sales[FOR product IN ('Mouse Pad', 'Bounce', 'Y Box')
,2008] = 1.3 * sales[CV(product), 2001] );
PRODUCT YEAR SALES
---------- ----- -------
Y Box 2008 77078
Bounce 2008 4888
Mouse Pad 2008 4358
3 rows selected.
Constants, Cell References,
Queries, et al…
RULES UPSERT ( -- Constants
sales[FOR product IN ('Mouse Pad', 'Bounce', 'Y Box')
,2002] = 1.3 * sales[CV(product), CV(year)-1] );
RULES UPSERT ( -- Cell References
sales[FOR (product, year) IN (
('Mouse Pad', 2002), ('Bounce',2002), ('Y Box',2002))]
= 1.3 * sales[CV(product), CV(year)-1] );
RULES UPSERT ( -- Queries
sales[FOR product IN (SELECT product FROM my_products)
,FOR year IN (2002)]
= 1.3 * sales[CV(product), CV(year)-1] );
PRODUCT YEAR SALES
---------- ----- -------
Y Box 2002 77078
Bounce 2002 4888
Mouse Pad 2002 4358
et allia – en trappe!
RULES UPSERT SEQUENTIAL ORDER (
sales['Bounce',
FOR year FROM 2004 TO 2001 DECREMENT 1]
= 1.3 * sales[CV(), CV()-1] )
PRODUCT YEAR SALES
-------- ----- -------
Bounce 2001 4097
Bounce 2002 4889
Bounce 2003
Bounce 2004
4 rows selected.
Ordering FOR loops
RULES UPSERT AUTOMATIC ORDER (
sales['Bounce',
FOR year FROM 2004 TO 2001 DECREMENT 1]
= 1.3 * sales[CV(), CV()-1] )
PRODUCT YEAR SALES
-------- ----- -------
Bounce 2001 4097
Bounce 2002 5326
Bounce 2003 6924
Bounce 2004 9001
4 rows selected.
ORDER BY in rules
RULES SEQUENTIAL ORDER (sales[ANY, ANY] = sales[cv(),cv()-1] )
ORA-32637: Self cyclic rule in sequential order MODEL
RULES (sales[ANY, ANY] ORDER BY YEAR ASC = sales[cv(),cv()-1])
PRODUCT YEAR SALES NEW_SALES
--------- ----- ------------ ----------
Bounce 1999 1,878 0
Bounce 2000 3,151 0
Bounce 2001 3,761 0
RULES (sales[ANY, ANY] ORDER BY YEAR DESC = sales[cv(),cv()-
1])
PRODUCT YEAR SALES NEW_SALES
--------- ----- ------------ ----------
Bounce 1999 1,878 0
Bounce 2000 3,151 1877.67
Bounce 2001 3,761 3151.35
NULL Measures
• Cells that exist in array but are NULL
• Cells not in the array at all
(treated as NULL)
<prior clauses of SELECT
statements>
MODEL [main] [RETURN {ALL|
UPDATED} ROWS]
[reference models]
[PARTITION BY (<cols>)]
DIMENSION BY (<cols>)
MEASURES (<cols>)
[IGNORE NAV] | [KEEP NAV]
[RULES...
KEEP NAV
SELECT product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
DIMENSION BY (product, year)
MEASURES (sales)
KEEP NAV
RULES UPSERT
(sales['Widget', 2003] = sales['Bounce', 2002]
+ sales['Bounce', 2001]
,sales['Widget', 2002] = sales['Bounce', 2002]
,sales['Widget', 2001] = sales['Bounce', 2001]);
PRODUCT YEAR SALES
-------- ----- ----------
Widget 2001 3760.51
Widget 2002
Widget 2003
3 rows selected.
IGNORE NAV
SELECT product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
DIMENSION BY (product, year)
MEASURES (sales)
IGNORE NAV
RULES UPSERT
(sales['Widget', 2003] = sales['Bounce', 2002]
+ sales['Bounce', 2001]
,sales['Widget', 2002] = sales['Bounce', 2002]
,sales['Widget', 2001] = sales['Bounce', 2001]);
PRODUCT YEAR SALES
-------- ----- ----------
Widget 2001 3760.51
Widget 2002 0
Widget 2003 3760.51
3 rows selected.
NULL Defaults
• 0 for numeric data
• Empty string '' for character/string data
• '01-JAN-2001' for date type data
• NULL for all other data types
NULL Cell Reference
• Positional
– sales [ANY]
– sales [NULL]
• Symbolic
– sales [product IS ANY]
– sales [product IS NULL]
– sales [product = NULL] -- FALSE
PRESENTV, PRESENTNNV
SELECT product, year, sales
FROM sales_view
WHERE country = 'Australia'
MODEL RETURN UPDATED ROWS
DIMENSION BY (product, year)
MEASURES (sales)
--IGNORE NAV -- Makes no difference
RULES UPSERT
(sales['Widget', 2003] = sales['Bounce', 2002]
+ sales['Bounce', 2001]
,sales['Widget', 2002] = PRESENTV(sales['Bounce', 2002],1,0)
,sales['Widget', 2001] = PRESENTNNV(sales['Bounce', 2001],1,0));
PRODUCT YEAR SALES
-------- ----- ----------
Widget 2001 1
Widget 2002 0
Widget 2003 3760.51
3 rows selected.
Reference Models
scott@sw10g> select * from exch_rates;
COUNTRY EXCHANGE_RATE
---------------- -------------
Poland .25
France .14
Australia .93
New Zealand 1.12
United Kingdom .45
5 rows selected.
…
COUNTRY YEAR SALES DOLLAR_SALES
---------------- ----- ------------ ------------
Australia 2001 1,164,871 1,083,330
France 2001 1,025,157 143,522
United Kingdom 2001 1,674,752 753,638
Reference Models
<prior clauses of SELECT statements>
MODEL [main] [RETURN {ALL|UPDATED} ROWS]
[reference models]
[PARTITION BY (<cols>)]
DIMENSION BY (<cols>)
MEASURES (<cols>)
[IGNORE NAV] | [KEEP NAV]
[RULES
[UPSERT | UPDATE]
[AUTOMATIC ORDER | SEQUENTIAL ORDER]
[ITERATE (n) [UNTIL <condition>] ]
( <cell_assignment> = <expression> ... )
Reference Models
SELECT country, year,
ROUND(sales) sales, ROUND(dollar_sales) dollar_sales
FROM sales_view
GROUP BY country, year
MODEL RETURN UPDATED ROWS
REFERENCE conv_ref ON
(SELECT country, exchange_rate FROM exch_rates)
DIMENSION BY (country) MEASURES (exchange_rate)
MAIN conversion
DIMENSION BY (country, year)
MEASURES (SUM(sales) sales, SUM(sales) dollar_sales)
RULES
(dollar_sales[FOR conversion.country IN
('France','Australia','United Kingdom'), 2001]
= sales[CV(country), CV(year)] * 1.0 *
conv_ref.exchange_rate[CV(country)]);
COUNTRY YEAR SALES DOLLAR_SALES
---------------- ----- ------------ ------------
Australia 2001 1,164,871 1,083,330
France 2001 1,025,157 143,522
United Kingdom 2001 1,674,752 753,638
3 rows selected.
Reference Models
SELECT country, year,
ROUND(sales) sales, ROUND(dollar_sales) dollar_sales
FROM sales_view
GROUP BY country, year
MODEL RETURN UPDATED ROWS
REFERENCE conv_ref ONREFERENCE conv_ref ON
(SELECT country, exchange_rate FROM exch_rates)(SELECT country, exchange_rate FROM exch_rates)
DIMENSION BY (country) MEASURES (exchange_rate)DIMENSION BY (country) MEASURES (exchange_rate)
MAINMAIN conversionconversion
DIMENSION BY (country, year)
MEASURES (SUM(sales) sales, SUM(sales) dollar_sales)
RULES
(dollar_sales[FOR conversion.country IN
('France','Australia','United Kingdom'), 2001]
= sales[CV(country), CV(year)] * 1.0 *
conv_ref.exchange_rate[CV(country)]conv_ref.exchange_rate[CV(country)]);
COUNTRY YEAR SALES DOLLAR_SALES
---------------- ----- ------------ ------------
Australia 2001 1,164,871 1,083,330
France 2001 1,025,157 143,522
United Kingdom 2001 1,674,752 753,638
3 rows selected.
Reference Models
SELECT country, year,SELECT country, year,
ROUND(sales) sales, ROUND(dollar_sales) dollar_salesROUND(sales) sales, ROUND(dollar_sales) dollar_sales
FROM sales_viewFROM sales_view
GROUP BY country, yearGROUP BY country, year
MODEL RETURN UPDATED ROWSMODEL RETURN UPDATED ROWS
REFERENCE conv_ref ON
(SELECT country, exchange_rate FROM exch_rates)
DIMENSION BY (country) MEASURES (exchange_rate)
MAIN conversion
DIMENSION BY (country, year)DIMENSION BY (country, year)
MEASURES (SUM(sales) sales, SUM(sales) dollar_sales)MEASURES (SUM(sales) sales, SUM(sales) dollar_sales)
RULESRULES
(dollar_sales[FOR conversion.country IN
('France','Australia','United Kingdom'), 2001]
= sales[CV(country), CV(year)] * 1.0 *
conv_ref.exchange_rate[CV(country)]);
COUNTRY YEAR SALES DOLLAR_SALES
---------------- ----- ------------ ------------
Australia 2001 1,164,871 1,083,330
France 2001 1,025,157 143,522
United Kingdom 2001 1,674,752 753,638
3 rows selected.
Australia
0.93
Eh?
SELECT v.country, v.year
,ROUND(SUM(sales)) sales
,ROUND(SUM(v.sales * r.exchange_rate)) dollar_sales
FROM sales_view v, exch_rates r
WHERE v.country IN
('France', 'Australia', 'United Kingdom')
AND v.year = 2001
AND v.country = r.country
GROUP BY v.country, v.year
ORDER BY v.country;
COUNTRY YEAR SALES DOLLAR_SALES
---------------- ----- ------------ ------------
Australia 2001 1,164,871 1,083,330
France 2001 1,025,157 143,522
United Kingdom 2001 1,674,752 753,638
3 rows selected.
Amortization
SELECT c, p, m, pp, ip
FROM mortgage
MODEL
REFERENCE R ON
(SELECT customer, fact, amt
FROM mortgage_facts
MODEL DIMENSION BY (customer, fact)
MEASURES (amount amt) RULES
(amt[any, 'PaymentAmt']= (amt[CV(),'Loan']*
Power(1+ (amt[CV(),'Annual_Interest']/100/12),amt[CV(),'Payments'])*
(amt[CV(),'Annual_Interest']/100/12)) /
(Power(1+(amt[CV(),'Annual_Interest']/100/12), amt[CV(),'Payments'])
- 1)))
DIMENSION BY (customer cust, fact)
MEASURES (amt)
MAIN amortization
PARTITION BY (customer c)
DIMENSION BY (0 p)
MEASURES (principalp pp, interestp ip, mort_balance m, customer mc)
RULES ITERATE(1000) UNTIL (ITERATION_NUMBER+1 =r.amt[mc[0],'Payments'])
(ip[ITERATION_NUMBER+1] = m[CV()-1] * r.amt[mc[0],
'Annual_Interest']/1200
,pp[ITERATION_NUMBER+1] = r.amt[mc[0], 'PaymentAmt'] - ip[CV()]
,m[ITERATION_NUMBER+1] = m[CV()-1] - pp[CV()])
ORDER BY c, p;
SELECT country, year,
ROUND(sales) sales, ROUND(dollar_sales)
dollar_sales
FROM sales_view
GROUP BY country, year
MODEL RETURN UPDATED ROWS
REFERENCE conv_ref ON
(SELECT country, exchange_rate FROM exch_rates)
DIMENSION BY (country) MEASURES (exchange_rate)
IGNORE NAV
MAIN conversion
DIMENSION BY (country, year)
MEASURES (SUM(sales) sales, SUM(sales)
dollar_sales) IGNORE NAV
RULES
(conv_ref.country['Australia'] = 0.97);
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Reference models are read only
SELECT country, year, SUM(sales) sales
FROM sales_view
GROUP BY country, year
MODEL RETURN UPDATED ROWS
MAIN conversion
DIMENSION BY (country, year)
MEASURES (SUM(sales) sales) IGNORE NAV
RULES
(sales[FOR country IN
('France','Australia','United Kingdom'),
2002]
= sales[CV(country), CV()-1] * 1.2);
ERROR at line 1:
ORA-00934: group function is not allowed here
Aggregate can’t be in SELECT/ORDER BY
SELECT *
FROM sales_view
WHERE country = 'Australia'
MODEL DIMENSION BY (product, year)
MEASURES (sales)
RULES UPSERT
(sales['Bounce', 2003] =
sales[CV(), CV()-1] +
(SELECT SUM(sales) FROM sales_view));
ERROR at line 1:
ORA-32620: illegal subquery within MODEL rules
MEASURES (sales,
(SELECT SUM(sales) FROM sales_view) AS grand_total)
RULES UPSERT
(sales['Bounce', 2003] = sales[CV(), CV()-1]
+ grand_total[CV(), CV()-1]);
Sub-queries
RULES UPSERT
(sales[FOR product IN (
WITH kludge_with AS
(SELECT prod_name FROM sh.products)
SELECT prod_name FROM kludge_with) , 2003]
= sales[CV(), CV()-1]);
ERROR at line 1:
ORA-32632: incorrect subquery in MODEL FOR cell index
RULES UPSERT
(sales[FOR cust_id IN
(SELECT cust_id FROM sh.customers), 2003]
= sales[CV(), CV()-1]);
ERROR at line 1:
ORA-32633: MODEL subquery FOR cell index returns too
many rows
FOR Construct Limitations
SELECT id, n FROM all_objects
WHERE object_id=1
MODEL
DIMENSION BY (object_id id)
MEASURES (object_name n)
RULES ITERATE (:v)
(n[iteration_number] =iteration_number)
ERROR at line 5:
ORA-32607: invalid ITERATE value in MODEL clause
SELECT id, n FROM all_objects
WHERE object_id=1
MODEL
DIMENSION BY (object_id id)
MEASURES (object_name n)
RULES ITERATE (100) UNTIL :v
(n[iteration_number] =iteration_number)
ITERATE UNTIL
Performance
• Replaces multiple joins/unions
• Scalable in size & parallelism
• Explain plan
Fill Dates
scott@sw10g> select * from customer;
NAME AMT DT
------ ---------- -----------
Scott 117 17-jan-2008
Scott 250 17-feb-2008
Scott 300 17-apr-2008
Scott 50 17-jun-2008
Wade 1231 17-mar-2008
Wade 2321 17-apr-2008
Wade 3122 17-sep-2008
Wade 59 17-oct-2008
8 rows selected.
Fill Dates
NAME MTH AMT CUM_AMT
------ --------- ---------- ----------
Scott January 117 117
Scott February 250 367
Scott March 0 367
Scott April 300 667
Scott May 0 667
Scott June 50 717
Scott July 0 717
Scott August 0 717
Scott September 0 717
Scott October 0 717
Scott November 0 717
Scott December 0 717
Wade January 0 0
Wade February 0 0
Wade March 1231 1231
Wade April 2321 3552
Wade May 0 3552
Wade June 0 3552
Wade July 0 3552
Wade August 0 3552
Wade September 3122 6674
Wade October 59 6733
Wade November 0 6733
Wade December 0 6733
24 rows selected.
NAME AMT DT
------ ---------- -----------
Scott 117 17-jan-2007
Scott 250 17-feb-2007
Scott 300 17-apr-2007
Scott 50 17-jun-2007
Wade 1231 17-mar-2007
Wade 2321 17-apr-2007
Wade 3122 17-sep-2007
Wade 59 17-oct-2007
8 rows selected.
Analytic Solution
SELECT date_fill.name, TO_CHAR(real_dt,'Month') mth, NVL(amt,0) amt
,NVL(SUM(amt) OVER (PARTITION BY date_fill.name
ORDER BY real_dt ),0) cum_amt
FROM (SELECT name, TRUNC(dt,'mm') dt, SUM(amt) amt
FROM customer
GROUP BY name, TRUNC(dt,'mm')
) actual_data,
(SELECT name, real_dt
FROM (SELECT DISTINCT name
FROM customer)
,(WITH mths AS (SELECT TRUNC(SYSDATE,'YYYY') real_dt
FROM DUAL CONNECT BY LEVEL <= 12)
SELECT ADD_MONTHS(real_dt,ROWNUM-1) real_dt FROM mths)
) date_fill
WHERE date_fill.real_dt = actual_data.dt(+)
AND date_fill.name = actual_data.name(+)
ORDER BY date_fill.name, date_fill.real_dt
/
Actual Data
Distinct list joined with conjured dates
Outer join actual data
with full date list
Analytic ExplainExecution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=13 Card=8 Bytes=31
1 0 SORT (ORDER BY) (Cost=13 Card=8 Bytes=312)
2 1 WINDOW (SORT) (Cost=13 Card=8 Bytes=312)
3 2 HASH JOIN (OUTER) (Cost=11 Card=8 Bytes=312)
4 3 VIEW (Cost=6 Card=8 Bytes=104)
5 4 MERGE JOIN (CARTESIAN) (Cost=6 Card=8 Bytes=104)
6 5 VIEW (Cost=2 Card=1 Bytes=6)
7 6 COUNT
8 7 VIEW (Cost=2 Card=1 Bytes=6)
9 8 CONNECT BY (WITHOUT FILTERING)
10 9 FAST DUAL (Cost=2 Card=1)
11 5 BUFFER (SORT) (Cost=6 Card=8 Bytes=56)
12 11 VIEW (Cost=4 Card=8 Bytes=56)
13 12 SORT (UNIQUE) (Cost=4 Card=8 Bytes=56)
14 13 TABLE ACCESS (FULL) OF 'CUSTOMER' (TABLE)
15 3 VIEW (Cost=4 Card=8 Bytes=208)
16 15 SORT (GROUP BY) (Cost=4 Card=8 Bytes=232)
17 16 TABLE ACCESS (FULL) OF 'CUSTOMER' (TABLE) (Cost=
Statistics
----------------------------------------------------
9 recursive calls
30 consistent gets
6 sorts (memory)
Model Solution
SELECT name, TO_CHAR(dt,'DD-MM-YYYY') dt, amt, cum_amt -- Model results
FROM (
SELECT name, TRUNC(dt, 'MM') dt, SUM(amt) amt
FROM customer
GROUP BY name, TRUNC(dt, 'MM')
)
MODEL
PARTITION BY (name)
DIMENSION BY (dt)
MEASURES (amt, cast(NULL AS NUMBER) cum_amt) -- Define calculated col
IGNORE NAV
RULES SEQUENTIAL ORDER(
amt[FOR dt FROM TO_DATE('01-01-2007', 'DD-MM-YYYY')
TO TO_DATE('01-12-2007', 'DD-MM-YYYY')
INCREMENT NUMTOYMINTERVAL(1, 'MONTH')
] = amt[CV(dt)] -- Apply amt for given date, if found
,cum_amt[ANY] = SUM(amt)[dt <= CV(dt)] -- Calculate cumulative
)
ORDER BY name, dt
/
Essentially
apply model to
this data set
Conjure dates
Model Explain
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5 Card=8 Bytes=232
1 0 SORT (ORDER BY) (Cost=5 Card=8 Bytes=232)
2 1 SQL MODEL (ORDERED) (Cost=5 Card=8 Bytes=232)
3 2 SORT (GROUP BY) (Cost=5 Card=8 Bytes=232)
4 3 TABLE ACCESS (FULL) OF 'CUSTOMER' (TABLE) (Cost=3 Ca
5 2 WINDOW (IN SQL MODEL) (SORT)
Statistics
----------------------------------------------------
5 recursive calls
15 consistent gets
4 sorts (memory)
…and no joins
Also noteworthy
cum_amt[any] = sum(amt)[dt <= cv(dt)] -- Sum dates before iteration date
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5 Card=8 Bytes=232
1 0 SORT (ORDER BY) (Cost=5 Card=8 Bytes=232)
2 1 SQL MODEL (ORDERED) (Cost=5 Card=8 Bytes=232)
3 2 SORT (GROUP BY) (Cost=5 Card=8 Bytes=232)
4 3 TABLE ACCESS (FULL) OF 'CUSTOMER' (TABLE) (Cost=3 Ca
5 2 WINDOW (IN SQL MODEL) (SORT)
cum_amt[any] = sum(amt)[any] -- Aggregate all dates, no window sort
Performance
• Replaces multiple joins/unions
• Scalable in size & parallelism
• Explain plan
216
+ 1
SELECT COUNT(*) FROM (
SELECT * FROM sales_mth_view
MODEL RETURN ALL ROWS
PARTITION BY (country)
DIMENSION BY (product, year, month)
MEASURES (sales)
RULES UPSERT SEQUENTIAL ORDER
(sales[ANY,ANY,ANY] = sales[CV(), CV(), CV()]*1.2
-- Plus forecast sales...
,sales[FOR product IN (SELECT prod_name FROM sh.products)
,FOR year FROM 2008 TO 2015 INCREMENT 1
,FOR month FROM 1 TO 12 INCREMENT 1
] = sales[CV(), CV()-8, CV()]*1.5)
)
sw10g> /
COUNT(*)
----------
156157
1 row selected.
Try that
in Excel…
Performance
• Replaces multiple joins/unions
• Scalable in size & parallelism
• Explain plan
Sequential Automatic
Cyclic
yn
Ordered
Fast Acyclic Cyclic
Fast
Order
Sequential Automatic
Cyclic
yn
Ordered
Fast Acyclic Cyclic
Fast
Order
SELECT country, product, year, sales
FROM sales_view
WHERE country IN ('Australia','Japan')
MODEL UNIQUE DIMENSION
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
RULES UPSERT SEQUENTIAL ORDER
(sales['Bounce',2003] = AVG(sales)[ANY,2002] * 1.5
,sales['Y Box', 2003] = sales['Bounce',2003] * .25);
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS
1 0 SQL MODEL (ORDERED FAST)
2 1 SORT (GROUP BY)
3 2 HASH JOIN
4 3 TABLE ACCESS (FULL) OF 'TIMES' (TABL
5 3 HASH JOIN
6 5 TABLE ACCESS (FULL) OF 'PRODUCTS'
7 5 HASH JOIN
8 7 HASH JOIN
9 8 TABLE ACCESS (FULL) OF 'COUNTR
10 8 TABLE ACCESS (FULL) OF 'CUSTOM
11 7 PARTITION RANGE (ALL)
12 11 TABLE ACCESS (FULL) OF 'SALES'
Cyclic
y
Cyclic
Order
SELECT country, product, year, sales
FROM sales_view
WHERE country in ('Australia','Japan')
MODEL UNIQUE DIMENSION
PARTITION BY (country)
DIMENSION BY (product, year)
MEASURES (sales)
IGNORE NAV RULES UPSERT AUTOMATIC ORDER
(sales['Y Box',2003] = 0.25 * sales['Bounce', 2003]
,sales['Bounce',2003] = sales['Y Box',2003]
+ sales['Bounce',2002]);
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS
1 0 SQL MODEL (CYCLIC)
2 1 SORT (GROUP BY)
3 2 HASH JOIN
4 3 TABLE ACCESS (FULL) OF 'TIMES' (TABLE)
5 3 HASH JOIN
6 5 TABLE ACCESS (FULL) OF 'PRODUCTS' (TABL
7 5 HASH JOIN
8 7 HASH JOIN
9 8 TABLE ACCESS (FULL) OF 'COUNTRIES'
...
Automatic
Why?
When?
1. New language?
2. Array/Sets
3. Recursion
4. Flexibility & Power
5. Can it be done in SQL?
sales[cv()-1]
• DECODE
• Analytics
• Model
– CV()
– Reference Model
DECODE
SELECT country
,SUM(DECODE(year,2007,sales,NULL)) current_year
,SUM(DECODE(year,2006,sales,NULL)) previous_year
,SUM(DECODE(year,2005,sales,NULL)) before_that
FROM sales_view
WHERE year BETWEEN 2005 AND 2007
GROUP BY country;
COUNTRY CURRENT_YEAR PREVIOUS_YEAR BEFORE_THAT
-------- ------------ ------------- -----------
Greece 27540 25067 20835
Italy 23738 20831 22867
DECODE
SELECT country, year
,SUM(DECODE(year,2007,sales,NULL)) current_year
,SUM(DECODE(year,2006,sales,NULL)) previous_year
,SUM(DECODE(year,2005,sales,NULL)) before_that
FROM sales_view
WHERE year BETWEEN 2005 AND 2007
GROUP BY country, year;
COUNTRY YEAR CURRENT_YEAR PREVIOUS_YEAR BEFORE_THAT
-------- ----- ------------ ------------- -----------
Italy 2005 22867
Italy 2006 20831
Italy 2007 23738
Greece 2005 20835
Greece 2006 25067
Greece 2007 27540
Analytics
SELECT country, year, current_year, previous_year, before_that
FROM (
SELECT year, country, tot_sales current_year
,LAG(tot_sales) OVER
(PARTITION BY country ORDER BY year) previous_year
,LAG(tot_sales,2) OVER
(PARTITION BY country ORDER BY year) before_that
FROM (
SELECT country
,year
,SUM(sales) tot_sales
FROM sales_view
WHERE year BETWEEN 2005 AND 2007
GROUP BY year, country)
) WHERE year = 2007;
COUNTRY YEAR CURRENT_YEAR PREVIOUS_YEAR BEFORE_THAT
---------- ----- ------------ ------------- -----------
Greece 2007 27540 25067 20835
Italy 2007 23738 20831 22867
Analytics
SELECT country, year, current_year, previous_year, before_that
FROM (
SELECT year, country, tot_sales current_year
,LAG(tot_sales) OVER
(PARTITION BY country ORDER BY year) previous_year
,LAG(tot_sales,2) OVER
(PARTITION BY country ORDER BY year) before_that
FROM (
SELECT country
,year
,SUM(sales) tot_sales
FROM sales_view
WHERE year BETWEEN 2005 AND 2007
GROUP BY year, country)
) WHERE year >= 2005;
COUNTRY YEAR CURRENT_YEAR PREVIOUS_YEAR BEFORE_THAT
---------- ----- ------------ ------------- -----------
Greece 2005 20835
Greece 2006 25067 20835
Greece 2007 27540 25067 20835
Italy 2005 22867
Italy 2006 20831 22867
Italy 2007 23738 20831 22867
Model – CV()
SELECT country, year, sales, previous_year, before_that
FROM sales_view
GROUP BY year, country
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (year)
MEASURES (SUM(sales) AS sales
,CAST(NULL AS NUMBER) previous_year
,CAST(NULL AS NUMBER) before_that)
RULES (
previous_year[2007] = sales[CV()-1]
,before_that [2007] = sales[CV()-2]
);
COUNTRY YEAR SALES PREVIOUS_YEAR BEFORE_THAT
-------- ----- ------------ ------------- -----------
Greece 2007 27,540 25067 20835
Italy 2007 23,738 20831 22867
Model – CV()
SELECT country, year, sales, previous_year, before_that
FROM sales_view
GROUP BY year, country
MODEL RETURN UPDATED ROWS
PARTITION BY (country)
DIMENSION BY (year)
MEASURES (SUM(sales) AS sales
,CAST(NULL AS NUMBER) previous_year
,CAST(NULL AS NUMBER) before_that)
RULES (
previous_year[ANY] = sales[CV()-1]
,before_that [ANY] = sales[CV()-2]
);
COUNTRY YEAR SALES PREVIOUS_YEAR BEFORE_THAT
-------- ----- ------------ ------------- -----------
Greece 2005 20,835
Greece 2006 25,067 20835
Greece 2007 27,540 25067 20835
Italy 2005 22,867
Italy 2006 20,831 22867
Italy 2007 23,738 20831 22867
Model - Reference
SELECT country, year, sales, prev, bef
FROM sales_view
GROUP BY country, year
MODEL
REFERENCE r ON
(WITH years AS (SELECT TO_CHAR(SYSDATE,'YYYY')-LEVEL+1 y
FROM DUAL CONNECT BY LEVEL <=10)
SELECT y, y-1 prev, y-2 bef FROM years)
DIMENSION BY (y)
MEASURES (prev, bef)
MAIN calc
PARTITION BY (country)
DIMENSION BY (year)
MEASURES (SUM(sales) AS sales
,CAST(NULL AS NUMBER) prev, 0 bef)
RULES (
prev[ANY] = sales[r.prev[CV(year)]]
,bef [ANY] = sales[r.bef [CV(year)]]
);
Give it time, it will grow on you…

More Related Content

What's hot

TECHTALK 20210126 Qlik Sense SaaSの 認証連携を詳細解説
TECHTALK 20210126 Qlik Sense SaaSの 認証連携を詳細解説TECHTALK 20210126 Qlik Sense SaaSの 認証連携を詳細解説
TECHTALK 20210126 Qlik Sense SaaSの 認証連携を詳細解説QlikPresalesJapan
 
Presentacion Pruebas
Presentacion PruebasPresentacion Pruebas
Presentacion Pruebasdajigar
 
Qlik Alerting で実現する Qlik Sense Enterprise Client-managed (Windows版) の高度でインテリジ...
Qlik Alerting で実現する Qlik Sense Enterprise Client-managed (Windows版) の高度でインテリジ...Qlik Alerting で実現する Qlik Sense Enterprise Client-managed (Windows版) の高度でインテリジ...
Qlik Alerting で実現する Qlik Sense Enterprise Client-managed (Windows版) の高度でインテリジ...QlikPresalesJapan
 
Qlik Sense SaaS向けコマンドラインツールのご紹介 - Windows/Linux/macOS対応"qlik"コマンド
Qlik Sense SaaS向けコマンドラインツールのご紹介 - Windows/Linux/macOS対応"qlik"コマンドQlik Sense SaaS向けコマンドラインツールのご紹介 - Windows/Linux/macOS対応"qlik"コマンド
Qlik Sense SaaS向けコマンドラインツールのご紹介 - Windows/Linux/macOS対応"qlik"コマンドQlikPresalesJapan
 
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介QlikPresalesJapan
 
Understanding my database through SQL*Plus using the free tool eDB360
Understanding my database through SQL*Plus using the free tool eDB360Understanding my database through SQL*Plus using the free tool eDB360
Understanding my database through SQL*Plus using the free tool eDB360Carlos Sierra
 
The art of system and solution testing
The art of system and solution testingThe art of system and solution testing
The art of system and solution testinggaoliang641
 
BSides Portland - Attacking Azure Environments with PowerShell
BSides Portland - Attacking Azure Environments with PowerShellBSides Portland - Attacking Azure Environments with PowerShell
BSides Portland - Attacking Azure Environments with PowerShellKarl Fosaaen
 
Qlik Tips 20220524 理解を促すビジュアライゼーション
Qlik Tips 20220524 理解を促すビジュアライゼーションQlik Tips 20220524 理解を促すビジュアライゼーション
Qlik Tips 20220524 理解を促すビジュアライゼーションQlikPresalesJapan
 
Qlik Cloudデータ統合:データ変換機能のご紹介
Qlik Cloudデータ統合:データ変換機能のご紹介Qlik Cloudデータ統合:データ変換機能のご紹介
Qlik Cloudデータ統合:データ変換機能のご紹介QlikPresalesJapan
 
Understanding SQL Trace, TKPROF and Execution Plan for beginners
Understanding SQL Trace, TKPROF and Execution Plan for beginnersUnderstanding SQL Trace, TKPROF and Execution Plan for beginners
Understanding SQL Trace, TKPROF and Execution Plan for beginnersCarlos Sierra
 
オンライン技術勉強会 20201217 QSEoWサーバー管理者向けトレーニング_3
オンライン技術勉強会 20201217 QSEoWサーバー管理者向けトレーニング_3オンライン技術勉強会 20201217 QSEoWサーバー管理者向けトレーニング_3
オンライン技術勉強会 20201217 QSEoWサーバー管理者向けトレーニング_3QlikPresalesJapan
 
[A23] Oracle移行を簡単に。レプリケーションテクノロジーを使いこなす by Keishi Miyachi
[A23] Oracle移行を簡単に。レプリケーションテクノロジーを使いこなす by Keishi Miyachi[A23] Oracle移行を簡単に。レプリケーションテクノロジーを使いこなす by Keishi Miyachi
[A23] Oracle移行を簡単に。レプリケーションテクノロジーを使いこなす by Keishi MiyachiInsight Technology, Inc.
 
utPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLutPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLSteven Feuerstein
 
TECHTALK 20230228 ビジネスユーザー向け機械学習入門 第3回~機械学習のモデルの評価と検証
TECHTALK 20230228 ビジネスユーザー向け機械学習入門 第3回~機械学習のモデルの評価と検証 TECHTALK 20230228 ビジネスユーザー向け機械学習入門 第3回~機械学習のモデルの評価と検証
TECHTALK 20230228 ビジネスユーザー向け機械学習入門 第3回~機械学習のモデルの評価と検証 QlikPresalesJapan
 
Argentesting 2019 - Testing exploratorio basado en sesiones
Argentesting 2019 - Testing exploratorio basado en sesionesArgentesting 2019 - Testing exploratorio basado en sesiones
Argentesting 2019 - Testing exploratorio basado en sesionesArgentesting
 
Tanel Poder - Scripts and Tools short
Tanel Poder - Scripts and Tools shortTanel Poder - Scripts and Tools short
Tanel Poder - Scripts and Tools shortTanel Poder
 

What's hot (20)

TECHTALK 20210126 Qlik Sense SaaSの 認証連携を詳細解説
TECHTALK 20210126 Qlik Sense SaaSの 認証連携を詳細解説TECHTALK 20210126 Qlik Sense SaaSの 認証連携を詳細解説
TECHTALK 20210126 Qlik Sense SaaSの 認証連携を詳細解説
 
Presentacion Pruebas
Presentacion PruebasPresentacion Pruebas
Presentacion Pruebas
 
Qlik Alerting で実現する Qlik Sense Enterprise Client-managed (Windows版) の高度でインテリジ...
Qlik Alerting で実現する Qlik Sense Enterprise Client-managed (Windows版) の高度でインテリジ...Qlik Alerting で実現する Qlik Sense Enterprise Client-managed (Windows版) の高度でインテリジ...
Qlik Alerting で実現する Qlik Sense Enterprise Client-managed (Windows版) の高度でインテリジ...
 
Oracle on AWS
Oracle on AWSOracle on AWS
Oracle on AWS
 
Qlik Sense SaaS向けコマンドラインツールのご紹介 - Windows/Linux/macOS対応"qlik"コマンド
Qlik Sense SaaS向けコマンドラインツールのご紹介 - Windows/Linux/macOS対応"qlik"コマンドQlik Sense SaaS向けコマンドラインツールのご紹介 - Windows/Linux/macOS対応"qlik"コマンド
Qlik Sense SaaS向けコマンドラインツールのご紹介 - Windows/Linux/macOS対応"qlik"コマンド
 
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
 
Understanding my database through SQL*Plus using the free tool eDB360
Understanding my database through SQL*Plus using the free tool eDB360Understanding my database through SQL*Plus using the free tool eDB360
Understanding my database through SQL*Plus using the free tool eDB360
 
The art of system and solution testing
The art of system and solution testingThe art of system and solution testing
The art of system and solution testing
 
BSides Portland - Attacking Azure Environments with PowerShell
BSides Portland - Attacking Azure Environments with PowerShellBSides Portland - Attacking Azure Environments with PowerShell
BSides Portland - Attacking Azure Environments with PowerShell
 
Proyecto de redes lan vpn
Proyecto de redes lan vpnProyecto de redes lan vpn
Proyecto de redes lan vpn
 
Qlik Tips 20220524 理解を促すビジュアライゼーション
Qlik Tips 20220524 理解を促すビジュアライゼーションQlik Tips 20220524 理解を促すビジュアライゼーション
Qlik Tips 20220524 理解を促すビジュアライゼーション
 
Qlik Cloudデータ統合:データ変換機能のご紹介
Qlik Cloudデータ統合:データ変換機能のご紹介Qlik Cloudデータ統合:データ変換機能のご紹介
Qlik Cloudデータ統合:データ変換機能のご紹介
 
Understanding SQL Trace, TKPROF and Execution Plan for beginners
Understanding SQL Trace, TKPROF and Execution Plan for beginnersUnderstanding SQL Trace, TKPROF and Execution Plan for beginners
Understanding SQL Trace, TKPROF and Execution Plan for beginners
 
オンライン技術勉強会 20201217 QSEoWサーバー管理者向けトレーニング_3
オンライン技術勉強会 20201217 QSEoWサーバー管理者向けトレーニング_3オンライン技術勉強会 20201217 QSEoWサーバー管理者向けトレーニング_3
オンライン技術勉強会 20201217 QSEoWサーバー管理者向けトレーニング_3
 
[A23] Oracle移行を簡単に。レプリケーションテクノロジーを使いこなす by Keishi Miyachi
[A23] Oracle移行を簡単に。レプリケーションテクノロジーを使いこなす by Keishi Miyachi[A23] Oracle移行を簡単に。レプリケーションテクノロジーを使いこなす by Keishi Miyachi
[A23] Oracle移行を簡単に。レプリケーションテクノロジーを使いこなす by Keishi Miyachi
 
utPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLutPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQL
 
TECHTALK 20230228 ビジネスユーザー向け機械学習入門 第3回~機械学習のモデルの評価と検証
TECHTALK 20230228 ビジネスユーザー向け機械学習入門 第3回~機械学習のモデルの評価と検証 TECHTALK 20230228 ビジネスユーザー向け機械学習入門 第3回~機械学習のモデルの評価と検証
TECHTALK 20230228 ビジネスユーザー向け機械学習入門 第3回~機械学習のモデルの評価と検証
 
SQA
SQASQA
SQA
 
Argentesting 2019 - Testing exploratorio basado en sesiones
Argentesting 2019 - Testing exploratorio basado en sesionesArgentesting 2019 - Testing exploratorio basado en sesiones
Argentesting 2019 - Testing exploratorio basado en sesiones
 
Tanel Poder - Scripts and Tools short
Tanel Poder - Scripts and Tools shortTanel Poder - Scripts and Tools short
Tanel Poder - Scripts and Tools short
 

Viewers also liked

Modul Komputer Akuntansi STIE Rahmaniyah
Modul Komputer Akuntansi STIE RahmaniyahModul Komputer Akuntansi STIE Rahmaniyah
Modul Komputer Akuntansi STIE Rahmaniyahcandra romanda
 
Improving Spreadsheet Test Practices
Improving Spreadsheet Test PracticesImproving Spreadsheet Test Practices
Improving Spreadsheet Test PracticesFelienne Hermans
 
Bold City: A Bold Vision for Cape Town Station
Bold City: A Bold Vision for Cape Town StationBold City: A Bold Vision for Cape Town Station
Bold City: A Bold Vision for Cape Town Stationfuturecapetown
 
NoSQL? No, SQL! - SQL, the underestimated "Big Data" technology
NoSQL? No, SQL! - SQL, the underestimated "Big Data" technologyNoSQL? No, SQL! - SQL, the underestimated "Big Data" technology
NoSQL? No, SQL! - SQL, the underestimated "Big Data" technologyDataGeekery
 
Modul Prod. Akuntansi Program Spreadsheet
Modul Prod. Akuntansi Program SpreadsheetModul Prod. Akuntansi Program Spreadsheet
Modul Prod. Akuntansi Program SpreadsheetRisdiana Hidayat
 
10 SQL Tricks that You Didn't Think Were Possible
10 SQL Tricks that You Didn't Think Were Possible10 SQL Tricks that You Didn't Think Were Possible
10 SQL Tricks that You Didn't Think Were PossibleLukas Eder
 
Rpp revisi 2016 spreadsheet x smk rpp diva pendidikan
Rpp revisi 2016 spreadsheet x smk   rpp diva pendidikanRpp revisi 2016 spreadsheet x smk   rpp diva pendidikan
Rpp revisi 2016 spreadsheet x smk rpp diva pendidikanDiva Pendidikan
 
Comparacion entre modelos_de_gestion_de_calidad_total
Comparacion entre modelos_de_gestion_de_calidad_totalComparacion entre modelos_de_gestion_de_calidad_total
Comparacion entre modelos_de_gestion_de_calidad_totallcastellar37
 

Viewers also liked (9)

TUGAS SIM
TUGAS SIMTUGAS SIM
TUGAS SIM
 
Modul Komputer Akuntansi STIE Rahmaniyah
Modul Komputer Akuntansi STIE RahmaniyahModul Komputer Akuntansi STIE Rahmaniyah
Modul Komputer Akuntansi STIE Rahmaniyah
 
Improving Spreadsheet Test Practices
Improving Spreadsheet Test PracticesImproving Spreadsheet Test Practices
Improving Spreadsheet Test Practices
 
Bold City: A Bold Vision for Cape Town Station
Bold City: A Bold Vision for Cape Town StationBold City: A Bold Vision for Cape Town Station
Bold City: A Bold Vision for Cape Town Station
 
NoSQL? No, SQL! - SQL, the underestimated "Big Data" technology
NoSQL? No, SQL! - SQL, the underestimated "Big Data" technologyNoSQL? No, SQL! - SQL, the underestimated "Big Data" technology
NoSQL? No, SQL! - SQL, the underestimated "Big Data" technology
 
Modul Prod. Akuntansi Program Spreadsheet
Modul Prod. Akuntansi Program SpreadsheetModul Prod. Akuntansi Program Spreadsheet
Modul Prod. Akuntansi Program Spreadsheet
 
10 SQL Tricks that You Didn't Think Were Possible
10 SQL Tricks that You Didn't Think Were Possible10 SQL Tricks that You Didn't Think Were Possible
10 SQL Tricks that You Didn't Think Were Possible
 
Rpp revisi 2016 spreadsheet x smk rpp diva pendidikan
Rpp revisi 2016 spreadsheet x smk   rpp diva pendidikanRpp revisi 2016 spreadsheet x smk   rpp diva pendidikan
Rpp revisi 2016 spreadsheet x smk rpp diva pendidikan
 
Comparacion entre modelos_de_gestion_de_calidad_total
Comparacion entre modelos_de_gestion_de_calidad_totalComparacion entre modelos_de_gestion_de_calidad_total
Comparacion entre modelos_de_gestion_de_calidad_total
 

Similar to Oracle SQL Model Clause

Make your data dance: PIVOT, UNPIVOT & GROUP BY extensions
Make your data dance: PIVOT, UNPIVOT & GROUP BY extensionsMake your data dance: PIVOT, UNPIVOT & GROUP BY extensions
Make your data dance: PIVOT, UNPIVOT & GROUP BY extensionsstewashton
 
Make your data dance: PIVOT and GROUP BY in Oracle SQL
Make your data dance: PIVOT and GROUP BY in Oracle SQLMake your data dance: PIVOT and GROUP BY in Oracle SQL
Make your data dance: PIVOT and GROUP BY in Oracle SQLstewashton
 
Make your data dance
Make your data danceMake your data dance
Make your data dancestewashton
 
MDX - What BI Developers Need To Know
MDX - What BI Developers Need To KnowMDX - What BI Developers Need To Know
MDX - What BI Developers Need To KnowMark Ginnebaugh
 
Activity: Figuring with Algorithms 2020
Activity: Figuring with Algorithms 2020Activity: Figuring with Algorithms 2020
Activity: Figuring with Algorithms 2020R. Sosa
 
Common SQL Programming Mistakes
Common SQL Programming MistakesCommon SQL Programming Mistakes
Common SQL Programming MistakesPlamen Ratchev
 
AP MIcro Perfect Competition
AP MIcro Perfect CompetitionAP MIcro Perfect Competition
AP MIcro Perfect CompetitionMrRed
 
Sq lite functions
Sq lite functionsSq lite functions
Sq lite functionspunu_82
 
Work in TDW
Work in TDWWork in TDW
Work in TDWsaso70
 
Performance e Produtividade: 2 Habilidades para Transformar seu Relacionament...
Performance e Produtividade: 2 Habilidades para Transformar seu Relacionament...Performance e Produtividade: 2 Habilidades para Transformar seu Relacionament...
Performance e Produtividade: 2 Habilidades para Transformar seu Relacionament...rcmoutinho
 
Neo4j Makes Graphs Easy: Nicole White
Neo4j Makes Graphs Easy: Nicole WhiteNeo4j Makes Graphs Easy: Nicole White
Neo4j Makes Graphs Easy: Nicole WhiteNeo4j
 
Econ606 chapter 10 2020
Econ606 chapter 10 2020Econ606 chapter 10 2020
Econ606 chapter 10 2020sakanor
 
Presentation cvp analysis 140908
Presentation cvp analysis 140908Presentation cvp analysis 140908
Presentation cvp analysis 140908dhiraj.gaur
 

Similar to Oracle SQL Model Clause (20)

Make your data dance: PIVOT, UNPIVOT & GROUP BY extensions
Make your data dance: PIVOT, UNPIVOT & GROUP BY extensionsMake your data dance: PIVOT, UNPIVOT & GROUP BY extensions
Make your data dance: PIVOT, UNPIVOT & GROUP BY extensions
 
Make your data dance: PIVOT and GROUP BY in Oracle SQL
Make your data dance: PIVOT and GROUP BY in Oracle SQLMake your data dance: PIVOT and GROUP BY in Oracle SQL
Make your data dance: PIVOT and GROUP BY in Oracle SQL
 
Make your data dance
Make your data danceMake your data dance
Make your data dance
 
Using Inner-Joins (SQL)
Using Inner-Joins (SQL)Using Inner-Joins (SQL)
Using Inner-Joins (SQL)
 
Inner joins
Inner joinsInner joins
Inner joins
 
MDX - What BI Developers Need To Know
MDX - What BI Developers Need To KnowMDX - What BI Developers Need To Know
MDX - What BI Developers Need To Know
 
Activity: Figuring with Algorithms 2020
Activity: Figuring with Algorithms 2020Activity: Figuring with Algorithms 2020
Activity: Figuring with Algorithms 2020
 
Sql
SqlSql
Sql
 
Common SQL Programming Mistakes
Common SQL Programming MistakesCommon SQL Programming Mistakes
Common SQL Programming Mistakes
 
V34 numeric function-c
V34  numeric function-cV34  numeric function-c
V34 numeric function-c
 
AP MIcro Perfect Competition
AP MIcro Perfect CompetitionAP MIcro Perfect Competition
AP MIcro Perfect Competition
 
Sql commands
Sql commandsSql commands
Sql commands
 
Sq lite functions
Sq lite functionsSq lite functions
Sq lite functions
 
Work in TDW
Work in TDWWork in TDW
Work in TDW
 
Ise 307- chapter 9
Ise 307- chapter 9 Ise 307- chapter 9
Ise 307- chapter 9
 
Performance e Produtividade: 2 Habilidades para Transformar seu Relacionament...
Performance e Produtividade: 2 Habilidades para Transformar seu Relacionament...Performance e Produtividade: 2 Habilidades para Transformar seu Relacionament...
Performance e Produtividade: 2 Habilidades para Transformar seu Relacionament...
 
Neo4j Makes Graphs Easy: Nicole White
Neo4j Makes Graphs Easy: Nicole WhiteNeo4j Makes Graphs Easy: Nicole White
Neo4j Makes Graphs Easy: Nicole White
 
340project Final
340project Final340project Final
340project Final
 
Econ606 chapter 10 2020
Econ606 chapter 10 2020Econ606 chapter 10 2020
Econ606 chapter 10 2020
 
Presentation cvp analysis 140908
Presentation cvp analysis 140908Presentation cvp analysis 140908
Presentation cvp analysis 140908
 

More from Scott Wesley

Oracle Text in APEX
Oracle Text in APEXOracle Text in APEX
Oracle Text in APEXScott Wesley
 
Being Productive in IT
Being Productive in ITBeing Productive in IT
Being Productive in ITScott Wesley
 
Oracle APEX Performance
Oracle APEX PerformanceOracle APEX Performance
Oracle APEX PerformanceScott Wesley
 
Oracle Forms to APEX conversion tool
Oracle Forms to APEX conversion toolOracle Forms to APEX conversion tool
Oracle Forms to APEX conversion toolScott Wesley
 
Utilising Oracle documentation effectively
Utilising Oracle documentation effectivelyUtilising Oracle documentation effectively
Utilising Oracle documentation effectivelyScott Wesley
 
Oracle 11g new features for developers
Oracle 11g new features for developersOracle 11g new features for developers
Oracle 11g new features for developersScott Wesley
 
Oracle PL/SQL - Creative Conditional Compilation
Oracle PL/SQL - Creative Conditional CompilationOracle PL/SQL - Creative Conditional Compilation
Oracle PL/SQL - Creative Conditional CompilationScott Wesley
 
Oracle PL/SQL Bulk binds
Oracle PL/SQL Bulk bindsOracle PL/SQL Bulk binds
Oracle PL/SQL Bulk bindsScott Wesley
 

More from Scott Wesley (8)

Oracle Text in APEX
Oracle Text in APEXOracle Text in APEX
Oracle Text in APEX
 
Being Productive in IT
Being Productive in ITBeing Productive in IT
Being Productive in IT
 
Oracle APEX Performance
Oracle APEX PerformanceOracle APEX Performance
Oracle APEX Performance
 
Oracle Forms to APEX conversion tool
Oracle Forms to APEX conversion toolOracle Forms to APEX conversion tool
Oracle Forms to APEX conversion tool
 
Utilising Oracle documentation effectively
Utilising Oracle documentation effectivelyUtilising Oracle documentation effectively
Utilising Oracle documentation effectively
 
Oracle 11g new features for developers
Oracle 11g new features for developersOracle 11g new features for developers
Oracle 11g new features for developers
 
Oracle PL/SQL - Creative Conditional Compilation
Oracle PL/SQL - Creative Conditional CompilationOracle PL/SQL - Creative Conditional Compilation
Oracle PL/SQL - Creative Conditional Compilation
 
Oracle PL/SQL Bulk binds
Oracle PL/SQL Bulk bindsOracle PL/SQL Bulk binds
Oracle PL/SQL Bulk binds
 

Recently uploaded

Call me @ 9892124323 Cheap Rate Call Girls in Vashi with Real Photo 100% Secure
Call me @ 9892124323  Cheap Rate Call Girls in Vashi with Real Photo 100% SecureCall me @ 9892124323  Cheap Rate Call Girls in Vashi with Real Photo 100% Secure
Call me @ 9892124323 Cheap Rate Call Girls in Vashi with Real Photo 100% SecurePooja Nehwal
 
ALSO dropshipping via API with DroFx.pptx
ALSO dropshipping via API with DroFx.pptxALSO dropshipping via API with DroFx.pptx
ALSO dropshipping via API with DroFx.pptxolyaivanovalion
 
Chintamani Call Girls: 🍓 7737669865 🍓 High Profile Model Escorts | Bangalore ...
Chintamani Call Girls: 🍓 7737669865 🍓 High Profile Model Escorts | Bangalore ...Chintamani Call Girls: 🍓 7737669865 🍓 High Profile Model Escorts | Bangalore ...
Chintamani Call Girls: 🍓 7737669865 🍓 High Profile Model Escorts | Bangalore ...amitlee9823
 
BPAC WITH UFSBI GENERAL PRESENTATION 18_05_2017-1.pptx
BPAC WITH UFSBI GENERAL PRESENTATION 18_05_2017-1.pptxBPAC WITH UFSBI GENERAL PRESENTATION 18_05_2017-1.pptx
BPAC WITH UFSBI GENERAL PRESENTATION 18_05_2017-1.pptxMohammedJunaid861692
 
Mature dropshipping via API with DroFx.pptx
Mature dropshipping via API with DroFx.pptxMature dropshipping via API with DroFx.pptx
Mature dropshipping via API with DroFx.pptxolyaivanovalion
 
BabyOno dropshipping via API with DroFx.pptx
BabyOno dropshipping via API with DroFx.pptxBabyOno dropshipping via API with DroFx.pptx
BabyOno dropshipping via API with DroFx.pptxolyaivanovalion
 
Halmar dropshipping via API with DroFx
Halmar  dropshipping  via API with DroFxHalmar  dropshipping  via API with DroFx
Halmar dropshipping via API with DroFxolyaivanovalion
 
Log Analysis using OSSEC sasoasasasas.pptx
Log Analysis using OSSEC sasoasasasas.pptxLog Analysis using OSSEC sasoasasasas.pptx
Log Analysis using OSSEC sasoasasasas.pptxJohnnyPlasten
 
Zuja dropshipping via API with DroFx.pptx
Zuja dropshipping via API with DroFx.pptxZuja dropshipping via API with DroFx.pptx
Zuja dropshipping via API with DroFx.pptxolyaivanovalion
 
Vip Model Call Girls (Delhi) Karol Bagh 9711199171✔️Body to body massage wit...
Vip Model  Call Girls (Delhi) Karol Bagh 9711199171✔️Body to body massage wit...Vip Model  Call Girls (Delhi) Karol Bagh 9711199171✔️Body to body massage wit...
Vip Model Call Girls (Delhi) Karol Bagh 9711199171✔️Body to body massage wit...shivangimorya083
 
Market Analysis in the 5 Largest Economic Countries in Southeast Asia.pdf
Market Analysis in the 5 Largest Economic Countries in Southeast Asia.pdfMarket Analysis in the 5 Largest Economic Countries in Southeast Asia.pdf
Market Analysis in the 5 Largest Economic Countries in Southeast Asia.pdfRachmat Ramadhan H
 
VIP Call Girls Service Miyapur Hyderabad Call +91-8250192130
VIP Call Girls Service Miyapur Hyderabad Call +91-8250192130VIP Call Girls Service Miyapur Hyderabad Call +91-8250192130
VIP Call Girls Service Miyapur Hyderabad Call +91-8250192130Suhani Kapoor
 
Accredited-Transport-Cooperatives-Jan-2021-Web.pdf
Accredited-Transport-Cooperatives-Jan-2021-Web.pdfAccredited-Transport-Cooperatives-Jan-2021-Web.pdf
Accredited-Transport-Cooperatives-Jan-2021-Web.pdfadriantubila
 
Data-Analysis for Chicago Crime Data 2023
Data-Analysis for Chicago Crime Data  2023Data-Analysis for Chicago Crime Data  2023
Data-Analysis for Chicago Crime Data 2023ymrp368
 
BigBuy dropshipping via API with DroFx.pptx
BigBuy dropshipping via API with DroFx.pptxBigBuy dropshipping via API with DroFx.pptx
BigBuy dropshipping via API with DroFx.pptxolyaivanovalion
 
CALL ON ➥8923113531 🔝Call Girls Chinhat Lucknow best sexual service Online
CALL ON ➥8923113531 🔝Call Girls Chinhat Lucknow best sexual service OnlineCALL ON ➥8923113531 🔝Call Girls Chinhat Lucknow best sexual service Online
CALL ON ➥8923113531 🔝Call Girls Chinhat Lucknow best sexual service Onlineanilsa9823
 
Cheap Rate Call girls Sarita Vihar Delhi 9205541914 shot 1500 night
Cheap Rate Call girls Sarita Vihar Delhi 9205541914 shot 1500 nightCheap Rate Call girls Sarita Vihar Delhi 9205541914 shot 1500 night
Cheap Rate Call girls Sarita Vihar Delhi 9205541914 shot 1500 nightDelhi Call girls
 

Recently uploaded (20)

Call me @ 9892124323 Cheap Rate Call Girls in Vashi with Real Photo 100% Secure
Call me @ 9892124323  Cheap Rate Call Girls in Vashi with Real Photo 100% SecureCall me @ 9892124323  Cheap Rate Call Girls in Vashi with Real Photo 100% Secure
Call me @ 9892124323 Cheap Rate Call Girls in Vashi with Real Photo 100% Secure
 
ALSO dropshipping via API with DroFx.pptx
ALSO dropshipping via API with DroFx.pptxALSO dropshipping via API with DroFx.pptx
ALSO dropshipping via API with DroFx.pptx
 
Delhi 99530 vip 56974 Genuine Escort Service Call Girls in Kishangarh
Delhi 99530 vip 56974 Genuine Escort Service Call Girls in  KishangarhDelhi 99530 vip 56974 Genuine Escort Service Call Girls in  Kishangarh
Delhi 99530 vip 56974 Genuine Escort Service Call Girls in Kishangarh
 
Chintamani Call Girls: 🍓 7737669865 🍓 High Profile Model Escorts | Bangalore ...
Chintamani Call Girls: 🍓 7737669865 🍓 High Profile Model Escorts | Bangalore ...Chintamani Call Girls: 🍓 7737669865 🍓 High Profile Model Escorts | Bangalore ...
Chintamani Call Girls: 🍓 7737669865 🍓 High Profile Model Escorts | Bangalore ...
 
BPAC WITH UFSBI GENERAL PRESENTATION 18_05_2017-1.pptx
BPAC WITH UFSBI GENERAL PRESENTATION 18_05_2017-1.pptxBPAC WITH UFSBI GENERAL PRESENTATION 18_05_2017-1.pptx
BPAC WITH UFSBI GENERAL PRESENTATION 18_05_2017-1.pptx
 
Mature dropshipping via API with DroFx.pptx
Mature dropshipping via API with DroFx.pptxMature dropshipping via API with DroFx.pptx
Mature dropshipping via API with DroFx.pptx
 
BabyOno dropshipping via API with DroFx.pptx
BabyOno dropshipping via API with DroFx.pptxBabyOno dropshipping via API with DroFx.pptx
BabyOno dropshipping via API with DroFx.pptx
 
Halmar dropshipping via API with DroFx
Halmar  dropshipping  via API with DroFxHalmar  dropshipping  via API with DroFx
Halmar dropshipping via API with DroFx
 
Sampling (random) method and Non random.ppt
Sampling (random) method and Non random.pptSampling (random) method and Non random.ppt
Sampling (random) method and Non random.ppt
 
Abortion pills in Doha Qatar (+966572737505 ! Get Cytotec
Abortion pills in Doha Qatar (+966572737505 ! Get CytotecAbortion pills in Doha Qatar (+966572737505 ! Get Cytotec
Abortion pills in Doha Qatar (+966572737505 ! Get Cytotec
 
Log Analysis using OSSEC sasoasasasas.pptx
Log Analysis using OSSEC sasoasasasas.pptxLog Analysis using OSSEC sasoasasasas.pptx
Log Analysis using OSSEC sasoasasasas.pptx
 
Zuja dropshipping via API with DroFx.pptx
Zuja dropshipping via API with DroFx.pptxZuja dropshipping via API with DroFx.pptx
Zuja dropshipping via API with DroFx.pptx
 
Vip Model Call Girls (Delhi) Karol Bagh 9711199171✔️Body to body massage wit...
Vip Model  Call Girls (Delhi) Karol Bagh 9711199171✔️Body to body massage wit...Vip Model  Call Girls (Delhi) Karol Bagh 9711199171✔️Body to body massage wit...
Vip Model Call Girls (Delhi) Karol Bagh 9711199171✔️Body to body massage wit...
 
Market Analysis in the 5 Largest Economic Countries in Southeast Asia.pdf
Market Analysis in the 5 Largest Economic Countries in Southeast Asia.pdfMarket Analysis in the 5 Largest Economic Countries in Southeast Asia.pdf
Market Analysis in the 5 Largest Economic Countries in Southeast Asia.pdf
 
VIP Call Girls Service Miyapur Hyderabad Call +91-8250192130
VIP Call Girls Service Miyapur Hyderabad Call +91-8250192130VIP Call Girls Service Miyapur Hyderabad Call +91-8250192130
VIP Call Girls Service Miyapur Hyderabad Call +91-8250192130
 
Accredited-Transport-Cooperatives-Jan-2021-Web.pdf
Accredited-Transport-Cooperatives-Jan-2021-Web.pdfAccredited-Transport-Cooperatives-Jan-2021-Web.pdf
Accredited-Transport-Cooperatives-Jan-2021-Web.pdf
 
Data-Analysis for Chicago Crime Data 2023
Data-Analysis for Chicago Crime Data  2023Data-Analysis for Chicago Crime Data  2023
Data-Analysis for Chicago Crime Data 2023
 
BigBuy dropshipping via API with DroFx.pptx
BigBuy dropshipping via API with DroFx.pptxBigBuy dropshipping via API with DroFx.pptx
BigBuy dropshipping via API with DroFx.pptx
 
CALL ON ➥8923113531 🔝Call Girls Chinhat Lucknow best sexual service Online
CALL ON ➥8923113531 🔝Call Girls Chinhat Lucknow best sexual service OnlineCALL ON ➥8923113531 🔝Call Girls Chinhat Lucknow best sexual service Online
CALL ON ➥8923113531 🔝Call Girls Chinhat Lucknow best sexual service Online
 
Cheap Rate Call girls Sarita Vihar Delhi 9205541914 shot 1500 night
Cheap Rate Call girls Sarita Vihar Delhi 9205541914 shot 1500 nightCheap Rate Call girls Sarita Vihar Delhi 9205541914 shot 1500 night
Cheap Rate Call girls Sarita Vihar Delhi 9205541914 shot 1500 night
 

Oracle SQL Model Clause

  • 1. The Model Clause Spreadsheet Techniques using SQL Scott Wesley
  • 2. Agenda • Concepts • Cell Referencing • Focus • Performance • Final thoughts…
  • 3. Any Model experts? SELECT c, p, m, pp, ip FROM mortgage MODEL REFERENCE R ON (SELECT customer, fact, amt FROM mortgage_facts MODEL DIMENSION BY (customer, fact) MEASURES (amount amt) RULES (amt[any, 'PaymentAmt']= (amt[CV(),'Loan']* Power(1+ (amt[CV(),'Annual_Interest']/100/12),amt[CV(),'Payments'])* (amt[CV(),'Annual_Interest']/100/12)) / (Power(1+(amt[CV(),'Annual_Interest']/100/12), amt[CV(),'Payments']) - 1))) DIMENSION BY (customer cust, fact) MEASURES (amt) MAIN amortization PARTITION BY (customer c) DIMENSION BY (0 p) MEASURES (principalp pp, interestp ip, mort_balance m, customer mc) RULES ITERATE(1000) UNTIL (ITERATION_NUMBER+1 =r.amt[mc[0],'Payments']) (ip[ITERATION_NUMBER+1] = m[CV()-1] * r.amt[mc[0], 'Annual_Interest']/1200 ,pp[ITERATION_NUMBER+1] = r.amt[mc[0], 'PaymentAmt'] - ip[CV()] ,m[ITERATION_NUMBER+1] = m[CV()-1] - pp[CV()]) ORDER BY c, p;
  • 4. FizzBuzz • Write a program that prints the numbers from 1 to 100. • But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. • For numbers which are multiples of both three and five print “FizzBuzz” http://tkyte.blogspot.com/2007/02/what-is-your-fizzbuzz-factor.html
  • 5. SQL> WITH data AS (SELECT LEVEL AS n FROM DUAL CONNECT BY LEVEL <= 100) SELECT n, NVL(CASE WHEN MOD(n,3) = 0 THEN 'Fizz' END || CASE WHEN MOD(n,5) = 0 THEN 'Buzz' END, TO_CHAR(n)) AS answer FROM data; N ANSWER ---- ----------- 1 1 2 2 3 Fizz 4 4 5 Buzz 6 Fizz 7 7 8 8 9 Fizz 10 Buzz 11 11 12 Fizz 13 13 14 14 15 FizzBuzz 16 16 17 17 18 Fizz ...
  • 6. Anthony Wilson said.... So... do we win points by using MODEL, or get thrown out of the interview on mental health grounds? Nobody in their right mind actually uses this stuff, right? :) select id, n from all_objects where object_id = 1 model dimension by (object_id id) measures (object_name n) rules ( n[for id from 1 to 100 increment 1] = to_char(cv(id)), n[mod(id, 3) = 0] = 'fizz', n[mod(id, 5) = 0] = 'buzz', n[mod(id, 15) = 0] = 'fizzbuzz' ) order by id
  • 8. Basic Syntax <prior clauses of SELECT statements> MODEL [main] [RETURN {ALL|UPDATED} ROWS] [reference models] [PARTITION BY (<cols>)] DIMENSION BY (<cols>) MEASURES (<cols>) [IGNORE NAV] | [KEEP NAV] [RULES [UPSERT | UPDATE] [AUTOMATIC ORDER | SEQUENTIAL ORDER] [ITERATE (n) [UNTIL <condition>] ] ( <cell_assignment> = <expression> ... )
  • 9. SELECT country ,year ,sales ,previous_year ,before_that FROM sales_view GROUP BY year, country -- Define model structure/options MODEL RETURN ALL ROWS PARTITION BY (country) DIMENSION BY (year) MEASURES (SUM(sales) AS sales -- Define 'calculated columns' ,CAST(NULL AS NUMBER) previous_year ,CAST(NULL AS NUMBER) before_that) -- Define rule options RULES AUTOMATIC ORDER ( -- Define actual rules previous_year[ANY] = sales[CV()-1] ,before_that [ANY] = sales[CV()-2] ) -- Define order of entire result set ORDER BY country, year; Apply model clause to this query
  • 10. Concepts Country Product Year Sales Partition Dimension Dimension Measure AUS HAMMER 2006 10 AUS NAIL 2006 200 NZ NAIL 2006 300 NZ DRILL 2007 50
  • 11. Dimension Country Product Year Sales Partition Dimension Dimension Measure <prior clauses of SELECT statements> MODEL [main] [RETURN {ALL|UPDATED} ROWS] [reference models] [PARTITION BY (<cols>)] DIMENSION BY (product p, year y) MEASURES (<cols>) [IGNORE NAV] | [KEEP NAV] [RULES …
  • 12. Measure Country Product Year Sales Partition Dimension Dimension Measure <prior clauses of SELECT statements> MODEL [main] [RETURN {ALL|UPDATED} ROWS] [reference models] [PARTITION BY (<cols>)] DIMENSION BY (<cols>) MEASURES (sales) [IGNORE NAV] | [KEEP NAV] [RULES …
  • 13. Partition Country Product Year Sales Partition Dimension Dimension Measure <prior clauses of SELECT statements> MODEL [main] [RETURN {ALL|UPDATED} ROWS] [reference models] [PARTITION BY (country)] DIMENSION BY (<cols>) MEASURES (<cols>) [IGNORE NAV] | [KEEP NAV] [RULES …
  • 14. Array 20 15 5 35 15 Hammer Drill Product 2006 2007 2008 C ountry Year Aus N Z
  • 15. Rules <prior clauses of SELECT statements> MODEL [main] [RETURN {ALL|UPDATED} ROWS] [reference models] [PARTITION BY (<cols>)] DIMENSION BY (<cols>) MEASURES (<cols>) [IGNORE NAV] | [KEEP NAV] [RULES [UPSERT | UPDATE] [AUTOMATIC ORDER | SEQUENTIAL ORDER] [ITERATE (n) [UNTIL <condition>] ] ( <cell_assignment> = <expression> ... )
  • 16. Rules COUNTRY PRODUCT YEAR SALES Partition Dimension Dimension Measure AUS Hammer 2006 20 AUS Hammer 2007 15 AUS Drill 2007 5 NZ Hammer 2006 15 NZ Hammer 2007 10 NZ Drill 2007 10 AUS Hammer 2008 35 AUS Drill 2008 15 NZ Hammer 2008 25 NZ Drill 2008 30 Original Data Rule Results Sales[Hammer,2008] = Sales[Hammer,2006]+Sales[Hammer,2007] Sales[Drill ,2008] = Sales[Drill,2007]*3
  • 18. Return Rows <prior clauses of SELECT statements> MODEL [main] [RETURN {ALL|UPDATED} ROWS] [reference models] [PARTITION BY (<cols>)] DIMENSION BY (<cols>) MEASURES (<cols>) [IGNORE NAV] | [KEEP NAV] [RULES [UPSERT | UPDATE] [AUTOMATIC ORDER | SEQUENTIAL ORDER] [ITERATE (n) [UNTIL <condition>] ] ( <cell_assignment> = <expression> ... )
  • 19. Rules COUNTRY PRODUCT YEAR SALES Partition Dimension Dimension Measure AUS Hammer 2006 20 AUS Hammer 2007 15 AUS Drill 2007 5 NZ Hammer 2006 15 NZ Hammer 2007 10 NZ Drill 2007 10 AUS Hammer 2008 35 AUS Drill 2008 15 NZ Hammer 2008 25 NZ Drill 2008 30 RETURN ALL ROWS RETURN UPDATED ROWS Sales[Hammer,2008] = Sales[Hammer,2006]+Sales[Hammer,2007] Sales[Drill ,2008] = Sales[Drill,2007]*3
  • 20. Positional Cell Referencing SELECT country, product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES ( sales['Bounce', 2000] = 10 ,sales['Bounce', 2008] = 20 ); COUNTRY PROD YEAR SALES ------------ ------------ ----- ---------- Australia Bounce 2000 10 Australia Bounce 2008 20
  • 21. Symbolic Cell Referencing SELECT country, product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES ( sales[prod = 'Bounce', year > 1999] = 10 ) ORDER BY country, product, year; COUNTRY PRODUCT YEAR SALES ------------ ------------ ----- ---------- Australia Bounce 2000 10 Australia Bounce 2001 10
  • 22. Multi-Cell Access on Right Side SELECT country, product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES ( sales['Bounce',2008] = 100 + MAX(sales) ['Bounce', year BETWEEN 1998 and 2002] ,sales['Y Box',2008] = 1.3 * PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY sales) [product in ('Bounce', 'Y Box'), year < 2003]); COUNTRY PRODUCT YEAR SALES ---------- -------- ----- ------- Australia Bounce 2008 3861 Australia Y Box 2008 4889
  • 23. Multi-Cell Access on Right Side SELECT country, product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES ( sales['Bounce',2008] = 100 + MAX(sales) ['Bounce', year BETWEEN 1998 and 2002] ,sales['Y Box',2008] = 1.3 * PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY sales) [product in ('Bounce', 'Y Box'), year < 2003]); COUNTRY PRODUCT YEAR SALES ---------- -------- ----- ------- Australia Bounce 2008 3861 Australia Y Box 2008 4889
  • 24. CV()
  • 25. SELECT country, product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES ( sales['Bounce', year BETWEEN 1995 AND 2002] = sales['Mouse Pad', CV(year)] + 0.2 * sales['Y Box', CV()]); COUNTRY PRODUCT YEAR SALES ---------- -------- ----- ------- Australia Bounce 1999 6061 Australia Bounce 2000 8154 Australia Bounce 2001 15211
  • 26. SELECT country, product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES ( sales['Bounce', year BETWEEN 1995 AND 2002] = sales['Mouse Pad', CV(year)] + 0.2 * sales['Y Box', CV()]); COUNTRY PRODUCT YEAR SALES ---------- -------- ----- ------- Australia Bounce 1999 6061 Australia Bounce 2000 8154 Australia Bounce 2001 15211
  • 27. SELECT country, product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES ( sales['Bounce', year BETWEEN 1995 AND 2002] = sales['Mouse Pad', CV(year)] + 0.2 * sales['Y Box', CV()]); COUNTRY PRODUCT YEAR SALES ---------- -------- ----- ------- Australia Bounce 1999 6061 Australia Bounce 2000 8154 Australia Bounce 2001 15211
  • 28. SELECT country, product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES ( sales['Bounce', 1999] = sales['Mouse Pad',1999]+0.2*sales['Y Box',1999] sales['Bounce', 2000] = sales['Mouse Pad',2000]+0.2*sales['Y Box',2000] sales['Bounce', 20001] = sales['Mouse Pad',2001]+0.2*sales['Y Box',2001]);
  • 30. SELECT country, product, year, sales, p_year, growth_pct FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales, 0 p_year, 0 growth_pct) RULES ( p_year[product IN ('Bounce','Y Box'), year BETWEEN 1998 and 2001] = sales[CV(product), CV(year) -1] ,growth_pct[product IN ('Bounce','Y Box'), year BETWEEN 1998 and 2001] = 100* (sales[CV(product), CV(year)] - sales[CV(product), CV(year) -1] ) / sales[CV(product), CV(year) -1]) ORDER BY country, product, year; COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT ---------- --------- ----- ------- ------- ---------- Australia Bounce 1999 1878 Australia Bounce 2000 3151 1878 67.83 Australia Bounce 2001 3761 3151 19.33 Australia Y Box 1999 13773 Australia Y Box 2000 27007 13773 96.09 Australia Y Box 2001 59291 27007 119.54
  • 31. SELECT country, product, year, sales, p_year, growth_pct FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales, 0 p_year, 0 growth_pct) RULES ( p_year[product IN ('Bounce','Y Box'), year BETWEEN 1998 and 2001] = sales[CV(product), CV(year) -1] ,growth_pct[product IN ('Bounce','Y Box'), year BETWEEN 1998 and 2001] = 100* (sales[CV(product), CV(year)] - sales[CV(product), CV(year) -1] ) / sales[CV(product), CV(year) -1]) ORDER BY country, product, year; COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT ---------- --------- ----- ------- ------- ---------- Australia Bounce 1999 1878 Australia Bounce 2000 3151 1878 67.83 Australia Bounce 2001 3761 3151 19.33 Australia Y Box 1999 13773 Australia Y Box 2000 27007 13773 96.09 Australia Y Box 2001 59291 27007 119.54
  • 32. SELECT country, product, year, sales, p_year, growth_pct FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales, 0 p_year, 0 growth_pct) RULES ( p_year[product IN ('Bounce','Y Box'), ANY] = sales[CV(product), CV(year) -1] ,growth_pct[product IN ('Bounce','Y Box'), year IS ANY] = 100* (sales[CV(product), CV(year)] - sales[CV(product), CV(year) -1] ) / sales[CV(product), CV(year) -1]) ORDER BY country, product, year; COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT ---------- --------- ----- ------- ------- ---------- Australia Bounce 1999 1878 Australia Bounce 2000 3151 1878 67.83 Australia Bounce 2001 3761 3151 19.33 Australia Y Box 1999 13773 Australia Y Box 2000 27007 13773 96.09 Australia Y Box 2001 59291 27007 119.54
  • 33. Analytics vs Model LAG(sales,1) OVER (PARTITION BY prod ORDER BY year) p_year p_year[prod IS ANY, year IS ANY] = sales[CV(prod), CV(year)-1] SAME! Or is it…?
  • 34. Model method: COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT ---------- --------- ----- ------------ ------- ---------- Australia Bounce 1999 1,878 Australia Bounce 2000 3,151 1878 67.83 Australia Bounce 2001 3,761 3151 19.33 Australia Bounce 2003 8,790 Analytic method: COUNTRY PRODUCT YEAR SALES P_YEAR GROWTH_PCT ---------- --------- ----- ------------ ------- ---------- Australia Bounce 1999 1,878 Australia Bounce 2000 3,151 1878 67.83 Australia Bounce 2001 3,761 3151 19.33 Australia Bounce 2003 8,790 3761 133.73
  • 35. Rule Repetition SELECT product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS DIMENSION BY (product, year) MEASURES (sales) RULES UPSERT ( sales['Mouse Pad', 2008] = 1.3 * sales['Mouse Pad', 2001] ,sales['Bounce', 2008] = 1.3 * sales['Bounce', 2001] ,sales['Y Box', 2008] = 1.3 * sales['Y Box', 2001] ); PRODUCT YEAR SALES ---------- ----- ------- Y Box 2008 77078 Bounce 2008 4888 Mouse Pad 2008 4358 3 rows selected.
  • 36. Symbolic Reference SELECT product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS DIMENSION BY (product, year) MEASURES (sales) RULES UPSERT ( sales[product IN ('Mouse Pad', 'Bounce', 'Y Box') ,2008] = 1.3 * sales[CV(product), 2001] ); no rows selected
  • 37. Positional Reference SELECT product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS DIMENSION BY (product, year) MEASURES (sales) RULES UPSERT ( sales[FOR product IN ('Mouse Pad', 'Bounce', 'Y Box') ,2008] = 1.3 * sales[CV(product), 2001] ); PRODUCT YEAR SALES ---------- ----- ------- Y Box 2008 77078 Bounce 2008 4888 Mouse Pad 2008 4358 3 rows selected.
  • 38. Constants, Cell References, Queries, et al… RULES UPSERT ( -- Constants sales[FOR product IN ('Mouse Pad', 'Bounce', 'Y Box') ,2002] = 1.3 * sales[CV(product), CV(year)-1] ); RULES UPSERT ( -- Cell References sales[FOR (product, year) IN ( ('Mouse Pad', 2002), ('Bounce',2002), ('Y Box',2002))] = 1.3 * sales[CV(product), CV(year)-1] ); RULES UPSERT ( -- Queries sales[FOR product IN (SELECT product FROM my_products) ,FOR year IN (2002)] = 1.3 * sales[CV(product), CV(year)-1] ); PRODUCT YEAR SALES ---------- ----- ------- Y Box 2002 77078 Bounce 2002 4888 Mouse Pad 2002 4358
  • 39. et allia – en trappe! RULES UPSERT SEQUENTIAL ORDER ( sales['Bounce', FOR year FROM 2004 TO 2001 DECREMENT 1] = 1.3 * sales[CV(), CV()-1] ) PRODUCT YEAR SALES -------- ----- ------- Bounce 2001 4097 Bounce 2002 4889 Bounce 2003 Bounce 2004 4 rows selected.
  • 40. Ordering FOR loops RULES UPSERT AUTOMATIC ORDER ( sales['Bounce', FOR year FROM 2004 TO 2001 DECREMENT 1] = 1.3 * sales[CV(), CV()-1] ) PRODUCT YEAR SALES -------- ----- ------- Bounce 2001 4097 Bounce 2002 5326 Bounce 2003 6924 Bounce 2004 9001 4 rows selected.
  • 41. ORDER BY in rules RULES SEQUENTIAL ORDER (sales[ANY, ANY] = sales[cv(),cv()-1] ) ORA-32637: Self cyclic rule in sequential order MODEL RULES (sales[ANY, ANY] ORDER BY YEAR ASC = sales[cv(),cv()-1]) PRODUCT YEAR SALES NEW_SALES --------- ----- ------------ ---------- Bounce 1999 1,878 0 Bounce 2000 3,151 0 Bounce 2001 3,761 0 RULES (sales[ANY, ANY] ORDER BY YEAR DESC = sales[cv(),cv()- 1]) PRODUCT YEAR SALES NEW_SALES --------- ----- ------------ ---------- Bounce 1999 1,878 0 Bounce 2000 3,151 1877.67 Bounce 2001 3,761 3151.35
  • 42. NULL Measures • Cells that exist in array but are NULL • Cells not in the array at all (treated as NULL) <prior clauses of SELECT statements> MODEL [main] [RETURN {ALL| UPDATED} ROWS] [reference models] [PARTITION BY (<cols>)] DIMENSION BY (<cols>) MEASURES (<cols>) [IGNORE NAV] | [KEEP NAV] [RULES...
  • 43. KEEP NAV SELECT product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS DIMENSION BY (product, year) MEASURES (sales) KEEP NAV RULES UPSERT (sales['Widget', 2003] = sales['Bounce', 2002] + sales['Bounce', 2001] ,sales['Widget', 2002] = sales['Bounce', 2002] ,sales['Widget', 2001] = sales['Bounce', 2001]); PRODUCT YEAR SALES -------- ----- ---------- Widget 2001 3760.51 Widget 2002 Widget 2003 3 rows selected.
  • 44. IGNORE NAV SELECT product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS DIMENSION BY (product, year) MEASURES (sales) IGNORE NAV RULES UPSERT (sales['Widget', 2003] = sales['Bounce', 2002] + sales['Bounce', 2001] ,sales['Widget', 2002] = sales['Bounce', 2002] ,sales['Widget', 2001] = sales['Bounce', 2001]); PRODUCT YEAR SALES -------- ----- ---------- Widget 2001 3760.51 Widget 2002 0 Widget 2003 3760.51 3 rows selected.
  • 45. NULL Defaults • 0 for numeric data • Empty string '' for character/string data • '01-JAN-2001' for date type data • NULL for all other data types
  • 46. NULL Cell Reference • Positional – sales [ANY] – sales [NULL] • Symbolic – sales [product IS ANY] – sales [product IS NULL] – sales [product = NULL] -- FALSE
  • 47. PRESENTV, PRESENTNNV SELECT product, year, sales FROM sales_view WHERE country = 'Australia' MODEL RETURN UPDATED ROWS DIMENSION BY (product, year) MEASURES (sales) --IGNORE NAV -- Makes no difference RULES UPSERT (sales['Widget', 2003] = sales['Bounce', 2002] + sales['Bounce', 2001] ,sales['Widget', 2002] = PRESENTV(sales['Bounce', 2002],1,0) ,sales['Widget', 2001] = PRESENTNNV(sales['Bounce', 2001],1,0)); PRODUCT YEAR SALES -------- ----- ---------- Widget 2001 1 Widget 2002 0 Widget 2003 3760.51 3 rows selected.
  • 48. Reference Models scott@sw10g> select * from exch_rates; COUNTRY EXCHANGE_RATE ---------------- ------------- Poland .25 France .14 Australia .93 New Zealand 1.12 United Kingdom .45 5 rows selected. … COUNTRY YEAR SALES DOLLAR_SALES ---------------- ----- ------------ ------------ Australia 2001 1,164,871 1,083,330 France 2001 1,025,157 143,522 United Kingdom 2001 1,674,752 753,638
  • 49. Reference Models <prior clauses of SELECT statements> MODEL [main] [RETURN {ALL|UPDATED} ROWS] [reference models] [PARTITION BY (<cols>)] DIMENSION BY (<cols>) MEASURES (<cols>) [IGNORE NAV] | [KEEP NAV] [RULES [UPSERT | UPDATE] [AUTOMATIC ORDER | SEQUENTIAL ORDER] [ITERATE (n) [UNTIL <condition>] ] ( <cell_assignment> = <expression> ... )
  • 50. Reference Models SELECT country, year, ROUND(sales) sales, ROUND(dollar_sales) dollar_sales FROM sales_view GROUP BY country, year MODEL RETURN UPDATED ROWS REFERENCE conv_ref ON (SELECT country, exchange_rate FROM exch_rates) DIMENSION BY (country) MEASURES (exchange_rate) MAIN conversion DIMENSION BY (country, year) MEASURES (SUM(sales) sales, SUM(sales) dollar_sales) RULES (dollar_sales[FOR conversion.country IN ('France','Australia','United Kingdom'), 2001] = sales[CV(country), CV(year)] * 1.0 * conv_ref.exchange_rate[CV(country)]); COUNTRY YEAR SALES DOLLAR_SALES ---------------- ----- ------------ ------------ Australia 2001 1,164,871 1,083,330 France 2001 1,025,157 143,522 United Kingdom 2001 1,674,752 753,638 3 rows selected.
  • 51. Reference Models SELECT country, year, ROUND(sales) sales, ROUND(dollar_sales) dollar_sales FROM sales_view GROUP BY country, year MODEL RETURN UPDATED ROWS REFERENCE conv_ref ONREFERENCE conv_ref ON (SELECT country, exchange_rate FROM exch_rates)(SELECT country, exchange_rate FROM exch_rates) DIMENSION BY (country) MEASURES (exchange_rate)DIMENSION BY (country) MEASURES (exchange_rate) MAINMAIN conversionconversion DIMENSION BY (country, year) MEASURES (SUM(sales) sales, SUM(sales) dollar_sales) RULES (dollar_sales[FOR conversion.country IN ('France','Australia','United Kingdom'), 2001] = sales[CV(country), CV(year)] * 1.0 * conv_ref.exchange_rate[CV(country)]conv_ref.exchange_rate[CV(country)]); COUNTRY YEAR SALES DOLLAR_SALES ---------------- ----- ------------ ------------ Australia 2001 1,164,871 1,083,330 France 2001 1,025,157 143,522 United Kingdom 2001 1,674,752 753,638 3 rows selected.
  • 52. Reference Models SELECT country, year,SELECT country, year, ROUND(sales) sales, ROUND(dollar_sales) dollar_salesROUND(sales) sales, ROUND(dollar_sales) dollar_sales FROM sales_viewFROM sales_view GROUP BY country, yearGROUP BY country, year MODEL RETURN UPDATED ROWSMODEL RETURN UPDATED ROWS REFERENCE conv_ref ON (SELECT country, exchange_rate FROM exch_rates) DIMENSION BY (country) MEASURES (exchange_rate) MAIN conversion DIMENSION BY (country, year)DIMENSION BY (country, year) MEASURES (SUM(sales) sales, SUM(sales) dollar_sales)MEASURES (SUM(sales) sales, SUM(sales) dollar_sales) RULESRULES (dollar_sales[FOR conversion.country IN ('France','Australia','United Kingdom'), 2001] = sales[CV(country), CV(year)] * 1.0 * conv_ref.exchange_rate[CV(country)]); COUNTRY YEAR SALES DOLLAR_SALES ---------------- ----- ------------ ------------ Australia 2001 1,164,871 1,083,330 France 2001 1,025,157 143,522 United Kingdom 2001 1,674,752 753,638 3 rows selected. Australia 0.93
  • 53. Eh? SELECT v.country, v.year ,ROUND(SUM(sales)) sales ,ROUND(SUM(v.sales * r.exchange_rate)) dollar_sales FROM sales_view v, exch_rates r WHERE v.country IN ('France', 'Australia', 'United Kingdom') AND v.year = 2001 AND v.country = r.country GROUP BY v.country, v.year ORDER BY v.country; COUNTRY YEAR SALES DOLLAR_SALES ---------------- ----- ------------ ------------ Australia 2001 1,164,871 1,083,330 France 2001 1,025,157 143,522 United Kingdom 2001 1,674,752 753,638 3 rows selected.
  • 54. Amortization SELECT c, p, m, pp, ip FROM mortgage MODEL REFERENCE R ON (SELECT customer, fact, amt FROM mortgage_facts MODEL DIMENSION BY (customer, fact) MEASURES (amount amt) RULES (amt[any, 'PaymentAmt']= (amt[CV(),'Loan']* Power(1+ (amt[CV(),'Annual_Interest']/100/12),amt[CV(),'Payments'])* (amt[CV(),'Annual_Interest']/100/12)) / (Power(1+(amt[CV(),'Annual_Interest']/100/12), amt[CV(),'Payments']) - 1))) DIMENSION BY (customer cust, fact) MEASURES (amt) MAIN amortization PARTITION BY (customer c) DIMENSION BY (0 p) MEASURES (principalp pp, interestp ip, mort_balance m, customer mc) RULES ITERATE(1000) UNTIL (ITERATION_NUMBER+1 =r.amt[mc[0],'Payments']) (ip[ITERATION_NUMBER+1] = m[CV()-1] * r.amt[mc[0], 'Annual_Interest']/1200 ,pp[ITERATION_NUMBER+1] = r.amt[mc[0], 'PaymentAmt'] - ip[CV()] ,m[ITERATION_NUMBER+1] = m[CV()-1] - pp[CV()]) ORDER BY c, p;
  • 55. SELECT country, year, ROUND(sales) sales, ROUND(dollar_sales) dollar_sales FROM sales_view GROUP BY country, year MODEL RETURN UPDATED ROWS REFERENCE conv_ref ON (SELECT country, exchange_rate FROM exch_rates) DIMENSION BY (country) MEASURES (exchange_rate) IGNORE NAV MAIN conversion DIMENSION BY (country, year) MEASURES (SUM(sales) sales, SUM(sales) dollar_sales) IGNORE NAV RULES (conv_ref.country['Australia'] = 0.97); ERROR at line 1: ORA-03113: end-of-file on communication channel Reference models are read only
  • 56. SELECT country, year, SUM(sales) sales FROM sales_view GROUP BY country, year MODEL RETURN UPDATED ROWS MAIN conversion DIMENSION BY (country, year) MEASURES (SUM(sales) sales) IGNORE NAV RULES (sales[FOR country IN ('France','Australia','United Kingdom'), 2002] = sales[CV(country), CV()-1] * 1.2); ERROR at line 1: ORA-00934: group function is not allowed here Aggregate can’t be in SELECT/ORDER BY
  • 57. SELECT * FROM sales_view WHERE country = 'Australia' MODEL DIMENSION BY (product, year) MEASURES (sales) RULES UPSERT (sales['Bounce', 2003] = sales[CV(), CV()-1] + (SELECT SUM(sales) FROM sales_view)); ERROR at line 1: ORA-32620: illegal subquery within MODEL rules MEASURES (sales, (SELECT SUM(sales) FROM sales_view) AS grand_total) RULES UPSERT (sales['Bounce', 2003] = sales[CV(), CV()-1] + grand_total[CV(), CV()-1]); Sub-queries
  • 58. RULES UPSERT (sales[FOR product IN ( WITH kludge_with AS (SELECT prod_name FROM sh.products) SELECT prod_name FROM kludge_with) , 2003] = sales[CV(), CV()-1]); ERROR at line 1: ORA-32632: incorrect subquery in MODEL FOR cell index RULES UPSERT (sales[FOR cust_id IN (SELECT cust_id FROM sh.customers), 2003] = sales[CV(), CV()-1]); ERROR at line 1: ORA-32633: MODEL subquery FOR cell index returns too many rows FOR Construct Limitations
  • 59. SELECT id, n FROM all_objects WHERE object_id=1 MODEL DIMENSION BY (object_id id) MEASURES (object_name n) RULES ITERATE (:v) (n[iteration_number] =iteration_number) ERROR at line 5: ORA-32607: invalid ITERATE value in MODEL clause SELECT id, n FROM all_objects WHERE object_id=1 MODEL DIMENSION BY (object_id id) MEASURES (object_name n) RULES ITERATE (100) UNTIL :v (n[iteration_number] =iteration_number) ITERATE UNTIL
  • 60. Performance • Replaces multiple joins/unions • Scalable in size & parallelism • Explain plan
  • 61. Fill Dates scott@sw10g> select * from customer; NAME AMT DT ------ ---------- ----------- Scott 117 17-jan-2008 Scott 250 17-feb-2008 Scott 300 17-apr-2008 Scott 50 17-jun-2008 Wade 1231 17-mar-2008 Wade 2321 17-apr-2008 Wade 3122 17-sep-2008 Wade 59 17-oct-2008 8 rows selected.
  • 62. Fill Dates NAME MTH AMT CUM_AMT ------ --------- ---------- ---------- Scott January 117 117 Scott February 250 367 Scott March 0 367 Scott April 300 667 Scott May 0 667 Scott June 50 717 Scott July 0 717 Scott August 0 717 Scott September 0 717 Scott October 0 717 Scott November 0 717 Scott December 0 717 Wade January 0 0 Wade February 0 0 Wade March 1231 1231 Wade April 2321 3552 Wade May 0 3552 Wade June 0 3552 Wade July 0 3552 Wade August 0 3552 Wade September 3122 6674 Wade October 59 6733 Wade November 0 6733 Wade December 0 6733 24 rows selected. NAME AMT DT ------ ---------- ----------- Scott 117 17-jan-2007 Scott 250 17-feb-2007 Scott 300 17-apr-2007 Scott 50 17-jun-2007 Wade 1231 17-mar-2007 Wade 2321 17-apr-2007 Wade 3122 17-sep-2007 Wade 59 17-oct-2007 8 rows selected.
  • 63. Analytic Solution SELECT date_fill.name, TO_CHAR(real_dt,'Month') mth, NVL(amt,0) amt ,NVL(SUM(amt) OVER (PARTITION BY date_fill.name ORDER BY real_dt ),0) cum_amt FROM (SELECT name, TRUNC(dt,'mm') dt, SUM(amt) amt FROM customer GROUP BY name, TRUNC(dt,'mm') ) actual_data, (SELECT name, real_dt FROM (SELECT DISTINCT name FROM customer) ,(WITH mths AS (SELECT TRUNC(SYSDATE,'YYYY') real_dt FROM DUAL CONNECT BY LEVEL <= 12) SELECT ADD_MONTHS(real_dt,ROWNUM-1) real_dt FROM mths) ) date_fill WHERE date_fill.real_dt = actual_data.dt(+) AND date_fill.name = actual_data.name(+) ORDER BY date_fill.name, date_fill.real_dt / Actual Data Distinct list joined with conjured dates Outer join actual data with full date list
  • 64. Analytic ExplainExecution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=13 Card=8 Bytes=31 1 0 SORT (ORDER BY) (Cost=13 Card=8 Bytes=312) 2 1 WINDOW (SORT) (Cost=13 Card=8 Bytes=312) 3 2 HASH JOIN (OUTER) (Cost=11 Card=8 Bytes=312) 4 3 VIEW (Cost=6 Card=8 Bytes=104) 5 4 MERGE JOIN (CARTESIAN) (Cost=6 Card=8 Bytes=104) 6 5 VIEW (Cost=2 Card=1 Bytes=6) 7 6 COUNT 8 7 VIEW (Cost=2 Card=1 Bytes=6) 9 8 CONNECT BY (WITHOUT FILTERING) 10 9 FAST DUAL (Cost=2 Card=1) 11 5 BUFFER (SORT) (Cost=6 Card=8 Bytes=56) 12 11 VIEW (Cost=4 Card=8 Bytes=56) 13 12 SORT (UNIQUE) (Cost=4 Card=8 Bytes=56) 14 13 TABLE ACCESS (FULL) OF 'CUSTOMER' (TABLE) 15 3 VIEW (Cost=4 Card=8 Bytes=208) 16 15 SORT (GROUP BY) (Cost=4 Card=8 Bytes=232) 17 16 TABLE ACCESS (FULL) OF 'CUSTOMER' (TABLE) (Cost= Statistics ---------------------------------------------------- 9 recursive calls 30 consistent gets 6 sorts (memory)
  • 65. Model Solution SELECT name, TO_CHAR(dt,'DD-MM-YYYY') dt, amt, cum_amt -- Model results FROM ( SELECT name, TRUNC(dt, 'MM') dt, SUM(amt) amt FROM customer GROUP BY name, TRUNC(dt, 'MM') ) MODEL PARTITION BY (name) DIMENSION BY (dt) MEASURES (amt, cast(NULL AS NUMBER) cum_amt) -- Define calculated col IGNORE NAV RULES SEQUENTIAL ORDER( amt[FOR dt FROM TO_DATE('01-01-2007', 'DD-MM-YYYY') TO TO_DATE('01-12-2007', 'DD-MM-YYYY') INCREMENT NUMTOYMINTERVAL(1, 'MONTH') ] = amt[CV(dt)] -- Apply amt for given date, if found ,cum_amt[ANY] = SUM(amt)[dt <= CV(dt)] -- Calculate cumulative ) ORDER BY name, dt / Essentially apply model to this data set Conjure dates
  • 66. Model Explain Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5 Card=8 Bytes=232 1 0 SORT (ORDER BY) (Cost=5 Card=8 Bytes=232) 2 1 SQL MODEL (ORDERED) (Cost=5 Card=8 Bytes=232) 3 2 SORT (GROUP BY) (Cost=5 Card=8 Bytes=232) 4 3 TABLE ACCESS (FULL) OF 'CUSTOMER' (TABLE) (Cost=3 Ca 5 2 WINDOW (IN SQL MODEL) (SORT) Statistics ---------------------------------------------------- 5 recursive calls 15 consistent gets 4 sorts (memory) …and no joins
  • 67. Also noteworthy cum_amt[any] = sum(amt)[dt <= cv(dt)] -- Sum dates before iteration date Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5 Card=8 Bytes=232 1 0 SORT (ORDER BY) (Cost=5 Card=8 Bytes=232) 2 1 SQL MODEL (ORDERED) (Cost=5 Card=8 Bytes=232) 3 2 SORT (GROUP BY) (Cost=5 Card=8 Bytes=232) 4 3 TABLE ACCESS (FULL) OF 'CUSTOMER' (TABLE) (Cost=3 Ca 5 2 WINDOW (IN SQL MODEL) (SORT) cum_amt[any] = sum(amt)[any] -- Aggregate all dates, no window sort
  • 68. Performance • Replaces multiple joins/unions • Scalable in size & parallelism • Explain plan
  • 69. 216 + 1 SELECT COUNT(*) FROM ( SELECT * FROM sales_mth_view MODEL RETURN ALL ROWS PARTITION BY (country) DIMENSION BY (product, year, month) MEASURES (sales) RULES UPSERT SEQUENTIAL ORDER (sales[ANY,ANY,ANY] = sales[CV(), CV(), CV()]*1.2 -- Plus forecast sales... ,sales[FOR product IN (SELECT prod_name FROM sh.products) ,FOR year FROM 2008 TO 2015 INCREMENT 1 ,FOR month FROM 1 TO 12 INCREMENT 1 ] = sales[CV(), CV()-8, CV()]*1.5) ) sw10g> / COUNT(*) ---------- 156157 1 row selected. Try that in Excel…
  • 70. Performance • Replaces multiple joins/unions • Scalable in size & parallelism • Explain plan
  • 72. Sequential Automatic Cyclic yn Ordered Fast Acyclic Cyclic Fast Order SELECT country, product, year, sales FROM sales_view WHERE country IN ('Australia','Japan') MODEL UNIQUE DIMENSION PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) RULES UPSERT SEQUENTIAL ORDER (sales['Bounce',2003] = AVG(sales)[ANY,2002] * 1.5 ,sales['Y Box', 2003] = sales['Bounce',2003] * .25); Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS 1 0 SQL MODEL (ORDERED FAST) 2 1 SORT (GROUP BY) 3 2 HASH JOIN 4 3 TABLE ACCESS (FULL) OF 'TIMES' (TABL 5 3 HASH JOIN 6 5 TABLE ACCESS (FULL) OF 'PRODUCTS' 7 5 HASH JOIN 8 7 HASH JOIN 9 8 TABLE ACCESS (FULL) OF 'COUNTR 10 8 TABLE ACCESS (FULL) OF 'CUSTOM 11 7 PARTITION RANGE (ALL) 12 11 TABLE ACCESS (FULL) OF 'SALES'
  • 73. Cyclic y Cyclic Order SELECT country, product, year, sales FROM sales_view WHERE country in ('Australia','Japan') MODEL UNIQUE DIMENSION PARTITION BY (country) DIMENSION BY (product, year) MEASURES (sales) IGNORE NAV RULES UPSERT AUTOMATIC ORDER (sales['Y Box',2003] = 0.25 * sales['Bounce', 2003] ,sales['Bounce',2003] = sales['Y Box',2003] + sales['Bounce',2002]); Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS 1 0 SQL MODEL (CYCLIC) 2 1 SORT (GROUP BY) 3 2 HASH JOIN 4 3 TABLE ACCESS (FULL) OF 'TIMES' (TABLE) 5 3 HASH JOIN 6 5 TABLE ACCESS (FULL) OF 'PRODUCTS' (TABL 7 5 HASH JOIN 8 7 HASH JOIN 9 8 TABLE ACCESS (FULL) OF 'COUNTRIES' ... Automatic
  • 74. Why? When? 1. New language? 2. Array/Sets 3. Recursion 4. Flexibility & Power 5. Can it be done in SQL?
  • 75. sales[cv()-1] • DECODE • Analytics • Model – CV() – Reference Model
  • 76. DECODE SELECT country ,SUM(DECODE(year,2007,sales,NULL)) current_year ,SUM(DECODE(year,2006,sales,NULL)) previous_year ,SUM(DECODE(year,2005,sales,NULL)) before_that FROM sales_view WHERE year BETWEEN 2005 AND 2007 GROUP BY country; COUNTRY CURRENT_YEAR PREVIOUS_YEAR BEFORE_THAT -------- ------------ ------------- ----------- Greece 27540 25067 20835 Italy 23738 20831 22867
  • 77. DECODE SELECT country, year ,SUM(DECODE(year,2007,sales,NULL)) current_year ,SUM(DECODE(year,2006,sales,NULL)) previous_year ,SUM(DECODE(year,2005,sales,NULL)) before_that FROM sales_view WHERE year BETWEEN 2005 AND 2007 GROUP BY country, year; COUNTRY YEAR CURRENT_YEAR PREVIOUS_YEAR BEFORE_THAT -------- ----- ------------ ------------- ----------- Italy 2005 22867 Italy 2006 20831 Italy 2007 23738 Greece 2005 20835 Greece 2006 25067 Greece 2007 27540
  • 78. Analytics SELECT country, year, current_year, previous_year, before_that FROM ( SELECT year, country, tot_sales current_year ,LAG(tot_sales) OVER (PARTITION BY country ORDER BY year) previous_year ,LAG(tot_sales,2) OVER (PARTITION BY country ORDER BY year) before_that FROM ( SELECT country ,year ,SUM(sales) tot_sales FROM sales_view WHERE year BETWEEN 2005 AND 2007 GROUP BY year, country) ) WHERE year = 2007; COUNTRY YEAR CURRENT_YEAR PREVIOUS_YEAR BEFORE_THAT ---------- ----- ------------ ------------- ----------- Greece 2007 27540 25067 20835 Italy 2007 23738 20831 22867
  • 79. Analytics SELECT country, year, current_year, previous_year, before_that FROM ( SELECT year, country, tot_sales current_year ,LAG(tot_sales) OVER (PARTITION BY country ORDER BY year) previous_year ,LAG(tot_sales,2) OVER (PARTITION BY country ORDER BY year) before_that FROM ( SELECT country ,year ,SUM(sales) tot_sales FROM sales_view WHERE year BETWEEN 2005 AND 2007 GROUP BY year, country) ) WHERE year >= 2005; COUNTRY YEAR CURRENT_YEAR PREVIOUS_YEAR BEFORE_THAT ---------- ----- ------------ ------------- ----------- Greece 2005 20835 Greece 2006 25067 20835 Greece 2007 27540 25067 20835 Italy 2005 22867 Italy 2006 20831 22867 Italy 2007 23738 20831 22867
  • 80. Model – CV() SELECT country, year, sales, previous_year, before_that FROM sales_view GROUP BY year, country MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (year) MEASURES (SUM(sales) AS sales ,CAST(NULL AS NUMBER) previous_year ,CAST(NULL AS NUMBER) before_that) RULES ( previous_year[2007] = sales[CV()-1] ,before_that [2007] = sales[CV()-2] ); COUNTRY YEAR SALES PREVIOUS_YEAR BEFORE_THAT -------- ----- ------------ ------------- ----------- Greece 2007 27,540 25067 20835 Italy 2007 23,738 20831 22867
  • 81. Model – CV() SELECT country, year, sales, previous_year, before_that FROM sales_view GROUP BY year, country MODEL RETURN UPDATED ROWS PARTITION BY (country) DIMENSION BY (year) MEASURES (SUM(sales) AS sales ,CAST(NULL AS NUMBER) previous_year ,CAST(NULL AS NUMBER) before_that) RULES ( previous_year[ANY] = sales[CV()-1] ,before_that [ANY] = sales[CV()-2] ); COUNTRY YEAR SALES PREVIOUS_YEAR BEFORE_THAT -------- ----- ------------ ------------- ----------- Greece 2005 20,835 Greece 2006 25,067 20835 Greece 2007 27,540 25067 20835 Italy 2005 22,867 Italy 2006 20,831 22867 Italy 2007 23,738 20831 22867
  • 82. Model - Reference SELECT country, year, sales, prev, bef FROM sales_view GROUP BY country, year MODEL REFERENCE r ON (WITH years AS (SELECT TO_CHAR(SYSDATE,'YYYY')-LEVEL+1 y FROM DUAL CONNECT BY LEVEL <=10) SELECT y, y-1 prev, y-2 bef FROM years) DIMENSION BY (y) MEASURES (prev, bef) MAIN calc PARTITION BY (country) DIMENSION BY (year) MEASURES (SUM(sales) AS sales ,CAST(NULL AS NUMBER) prev, 0 bef) RULES ( prev[ANY] = sales[r.prev[CV(year)]] ,bef [ANY] = sales[r.bef [CV(year)]] );
  • 83. Give it time, it will grow on you…

Editor's Notes

  1. This is my basic agenda for today. I hope you come out of it understand how to use the model clause and when/where you start using it, particular to replace spreadsheet functionality.
  2. Experts can either save me time and come up to explain this, or leave the room as not to embarrass me!
  3. Inspiration for this presentation when I saw a blog from Tom Kyte talking about “Why can’t programmers program?”. The following example was posed, something you might see in a Year 12 computing exam. Someone said he thought it was an old university drinking game (one that I’d fail badly)
  4. Various responses were given, I took best of breed and cleaned it to this level.
  5. But someone suggested this… so I wondered how it worked. Not having worked on a 10g db before, the only other time I remember seeing it was in a presentation by Penny where she labeled it a real beast! It’s really not too hard to understand, I want to break it down and demystify it for all of you.
  6. I’ve always wanted to include a pie chart in my presentation. Model clause is just like a spreadsheet, I love spreadsheets as my colleagues can testify. I have a spreadsheet for everything. Here we’re going to combing SQL &amp; spreadsheets, with a little bit of craft. I mean, who’s had a user who’s asked “can’t we just have it in a spreadsheet?” As it says in a 2003 Oracle White paper, it’s a good replacement for spreadsheets which all businesses know can be dodgy.
  7. Not all features of model illustrated here, but it’s core functionality most likely to be used, and those being covered today. I’ll come back to this slide when I can
  8. Identifying characteristics like Date, Region, Product
  9. Analogous to the measures of a fact table in a star schema. Sales / Cost Each cell is accessed within its partition by specifying its full combination of dimensions
  10. Similar to your analytical functions, only applies rules within each partition. Each partition is viewed by the formulas as an independent array.
  11. Now the business end of the clause, in particular the cell assignments.
  12. All calculations done on database. Model is the last clause processed in the query except the final order by. Does not update or insert data in existing tables – but of course you can supply it to an insert/update/merge statement. So we can use Model to just view the rows we logically create or update. Convenient way to limit result to newly calculated values. Again useful to apply to our DML.
  13. Back to our rules slide… could also be a better version of group by rollup
  14. Now to revert back to the examples in the SH schema. (Remember this is an old sample schema with old data – Model has been around since 2003 and still not widely adopted) Single cell access. For creation of new cells, such as projections for future years, we need to use these positional references, or FOR loops discussed later. Positional both updates and inserts – UPSERT.
  15. Multi-cell access – update only. Also referred to multi cell access on the left side. Update all rows after 1999 for WHERE WE ALREADY HAVE ROWS. Conditions such as &amp;lt;&amp;gt; IN BETWEEN, I like to think of it as boolean comparisons Symbolic powerful but solely for updating cells. If any symbolic use in any dimension, will update only. FOR loops provide concise technique for creating multiple cells from a single formula such as this.
  16. Simple aggregate functions, like finding 100 more than the max sales for Bounce between those years
  17. Or analytical functions like finding 30% more of the median sales for those products for years less than 2003. Instantly, we’ve got more power and potential than spreadsheets, but using the same type of cell referencing as a basis.
  18. Used on right side of formulas to copy left side specifications that refer to multiple cells. Each years sales for Bounce is sum of Mouse Pad and 20% of Y Box sales for that year. Few things to note.
  19. Dimension as argument to CV() is optional, uses positional reference.
  20. Might have spotted lack of data. Data in DB only for 1999 – 2001, and since this uses symbolic references, data is only updated, not created.
  21. So it’s the same as writing multiple rules, evaluating to 3 separate rules instead of one compact and flexible rule It’s almost equivalent to a SQL join. It’s imperative to the efficient usage of the model clause.
  22. Now we start getting into some impressive expressions – inter-row calculations.
  23. Here is a common performance and readability issue – referring to previous years sales. We can do this with analytical functions, but only to a certain extent. There are restrictions on where in the query it may be present, and when placing values in calculations, you really need to use an inline view to make it readable. Here we need to select the column, define the measure, define the rule – and we have a calculated field
  24. A growth calculated column has been added, referring to the value of last years sales multiple times in the calculation rather simply.
  25. dimension IS ANY = Symbolic ANY = Positional, but treated as symbolic Either prevents cell insertion because it really means (dimension is not null or dimension is null)
  26. What’s the difference between these two functions? Although note it’s a little easier to reference year-1 without needing to eliminate it from the final result set. We’ll explore that a little further later on. Now to focus…
  27. If we want to start forecasting for data for several certain products, I could list out several rules. This could quickly get beyond manageable, and doesn’t demonstrate code reuse.
  28. We could use a familiar statement, but this is symbolic notation which doesn’t allow creation of rows. You’d get UPDATE behaviour even though you state UPSERT.
  29. This is where the for loop is handy. Think of it like a tool to make a single formula generate multiple formulas with positional references, thus allowing UPSERT. You can also see how we begin to get the power of PL/SQL-esque constructs in SQL.
  30. Many options available for the FOR construct. All these return the same results. The last option opens up a world of possibilities, for example introducing new data.
  31. Another FOR loop construct highlights a trap to be careful of. Something always to be wary of when assessing results is rule evaluation order. Take SEQUENTIAL order, which is the default In this case, the FOR construct rules are evaluated in the order they are generated.
  32. Adding a little French culture here… When explicitly using AUTOMATIC order, Oracle knows that there is a dependency starting from 2000. So you get vastly different results! There are a number of other scenarios to consider with FOR loops that I don’t have time to go into today, relating to usage of UPDATE, UPSERT, or UPSERT ALL. Just be aware of it if your results or performance are unexpected.
  33. We can have an order by for each rule as well, and same cautions apply Sequential order just can’t refer to itself without further direction. Order by ascending is going to have the same issue when travelling down the list. So we can order by desc to ensure correct results.
  34. Not too much of a difference, unless you have some records with null sales figures
  35. If we have a table of exchange rates, and want to combine it with our data from the Model query
  36. We can start using something called reference models, this little baby here…
  37. Which translates into this query.
  38. It looks daunting, but note we have exactly the same type of query you’ve been seeing all morning, with our little FOR loop here
  39. But this time we also have a read only reference model. Note the alias and reference semantics. There’s no reason you can’t have more than one reference model either, note the “1.0” where the documented example had a growth rate as well.
  40. Some of the sharper ones out there still awake may be thinking, eh? Why don’t I just use a simple join?! Sure, if this example is all you need to do, stick with the wheel that works, but…
  41. … remember our amortization example? Please believe me when I say it’s going to be a little difficult converting that back to a simple join. There’s recursion, multi-dimensional reference model and a heavy need for nurofen in there…
  42. Good segue onto restrictions… We all want to know what sort of restrictions apply to new features. I remember back in 8i materialized views were patience building with all the restrictions one would face for fast refresh. We don’t really have that here. Most are pretty obvious. Data-warehousing guide lists quite a few, but most are concerned with semantics already mentioned. Such as using decrement instead of increment -1 Here are some examples of what not to do… Don’t do this… although at this stage this is a bug – but you can’t update a reference model. Try in 11g? They also can’t have a partition clause, they don’t need it – it’s not relevant.
  43. The measure is an important and flexible part of the model clause.
  44. Only time sub-queries are allowed in the rules is in the FOR construct. Something like this would need to be re-written into the measure
  45. Sub-query can’t contain a WITH, or contain over 10,000 rows. And really, if you’ve got that many rows in your sub-query, are you approaching the problem correctly?
  46. You can’t supply a bind variable for the number of iterations you desire. However you can define a figure larger than expected, and define a bind variable where to iterate until.
  47. For starters, the sheer concept of using model clause over past concepts is we no longer need to use multiple joins to the same data source and/or add unions to our dataset. We can query the data set we’d like to manipulate and apply our entire rule set over the single set of data.
  48. To follow this scenario, here is a simple list of customers. But in a report, we want to fill in missing months and add cumulative figure.
  49. To follow this scenario, given a simple list of customers. In a report, we want to fill in missing months and add cumulative figure.
  50. Tell model what you want, optimizer figures it out for you. Don’t worry about analytics
  51. Model clause computation is scalable in terms of the number of processors you have. That goes for most parallel queries you may have worked with in the past. The way it’s achieved in the Model computation is via the partition by clause. It essentially creates parallel query slaves for each partition, and each slave independently evaluates the rules based on the data it receives. Obviously if your partition has low cardinality, the level of parallelism will be limited. Documentation even suggests if no partition clause is present, it may consider dimensions for partitioning.
  52. Oracle’s explain plans are fully aware of model computation. There is a line in the query’s main explain plan output showing the model and algorithm used. Reference models are tagged with the keyword reference.
  53. Explain plan detail is predominantly based on the order of evaluation of the rules. Sequential vs Automatic If automatic, then are there any cyclic dependencies in the formulas? FAST if left side cell references are single cell references and aggregates, if any, are simple arithmetic non-distinct aggregates like SUM, COUNT, AVG etc. According to the documentation, basically the further to the left on my wonderful chart here, the less CPU intensive your query will be. I analysed similar queries using tkprof and Tom Kyte’s runstats test harness for latches and couldn’t find any significant differences between these scenarios. However, for your particular situation, take a leaf out of Connor’s book and prove to yourself that the example you would like to use does actually perform better depending on how it’s written.
  54. Performance is an important aspect of development. Despite what some DBAs believe, us developers want to make sure our queries run like greased lightning, and we want to show our skills in getting the job done efficiently. Model clause is up for that.
  55. When: As a developer you may have trained your eyes to see solutions using decode, subquery, unions, analytics, or a ultimately a combination. Over time you’ll see opportunities for the model clause, just as we’ve been finding opportunities for analytics more &amp; more ever since 8.1.7 – to the point where Tom Kyte is thinking of publishing a book solely on analytical functions. Why: It’s almost like a new language, where you’ll start to think about your data and results sets differently. I actually stumbled across the patent for this concept during my research Procedural programmers might find the array access to rows and set based programming an easy transition. Further allowing you to finalise your solutions in SQL without the need for PL/SQL Something I didn’t get a chance to go into was recursion. The power of recursion up to 9i relied on PL/SQL, the model clause allows recursion solely using SQL Combines procedural flexibility with set based processing power. Just consider memory requirements. Some cases will allow you to move PL/SQL logic to SQL, hence removing context switching and ultimately improving performance.Hence it gives you the opportunity to do even more things exclusively in SQL that would normally require some PL/SQL.Golden rule? Can it be done in SQL?
  56. The Model clause may seem more like a niche addition to SQL rather than a long-awaited solution. Once this new feature has been accepted and used by a large number of developers, its usefulness will grow as developers will undoubtedly discover clever and unexpected uses for it. In other words, give it time, and it will grow on you. - Anthony Molinaro