Más contenido relacionado La actualidad más candente (20) Similar a Polymorphic Table Functions in SQL (20) Polymorphic Table Functions in SQL1. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Your PL/SQL Office Hours session will begin
soon…
Polymorphic Table Functions!
with
Chris Saxon, @ChrisRSaxon & @SQLDaily
https://www.youtube.com/c/TheMagicofSQL
https://blogs.oracle.com/sql
Steven Feuerstein, @sfonplsql
http://www.youtube.com/c/PracticallyPerfectPLSQL
http://stevenfeuersteinonplsql.blogspot.com/
2. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
Polymorphic
Table Functions
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
Added in Oracle Database 18c, Polymorphic Table Functions
(PTFs) allow you do dynamically manipulate a result set at
runtime.
This means you can add or remove columns from a table,
based on input parameters
3. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
Why would
I want to do
this?!
Ryan McGuire / Gratisography
4. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
C,S,V =>
Dynamic
Customer Total Orders
Best customer 1,422
2nd best customer 1,000
All other customers 6,502
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
PTF Use Cases
CSV to Column conversion
Inspect CSV files and automatically split
the fields into columns
Dynamic Pivot
Generate pivoted column names based
on a row source
Top-N+
Like a standard Top-N query, but with an
extra row, summarizing all remaining data
5. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
To build a PTF, you need two things
A package
The package is the engine of the PTF. This must include a describe function. This tells
the database which columns are in the output
To assign values for each row to the new columns, you use a fetch_rows procedure
The function itself
You can create the PTF itself within the package
Or as a standalone function
Defining PTFs
6. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
create or replace package add_cols_pkg as
function describe (
tab in out dbms_tf.table_t,
cols dbms_tf.columns_t
) return dbms_tf.describe_t;
procedure fetch_rows ;
end add_cols_pkg;
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
Assign values
(optional)
Define new s
7. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
create or replace function add_columns (
tab table,
cols columns
) return
table pipelined
table polymorphic
using add_cols_pkg;
/
8. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
create or replace function add_columns (
tab table,
cols columns
) return
table pipelined
table polymorphic
using add_cols_pkg;
/
PTFs introduce two new "data types":
table
The input table for the PTF
Every PTF must have one of these
columns pseudo operator
A list of identifiers. These could be
existing columns in the table, or new
columns you want to add
9. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
create or replace function add_columns (
tab table,
cols columns
) return
table pipelined
table polymorphic
using add_cols_pkg;
/
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
In the polymorphic clause you
define it as using row or table
semantics.
With row semantics, the input is a
single row.
With table semantics, the input is a set
of rows. This allows you to sort the
input
The using clause states which package
contains the implementation of the PTF
10. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
describe function
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
You must have one of one of these in your package
This tells the database which columns will be in the result set
The following describe body adds columns to the output
11. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
begin
for i in 1 .. cols.count loop
new_cols(i) := dbms_tf.column_metadata_t (
name => cols(i),
type => dbms_tf.type_number
);
end loop;
return dbms_tf.describe_t ( new_columns => new_cols );
end;
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
This builds up an array of definitions for the new columns
dbms_tf.column_metadata_t defines their properties
12. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
begin
for i in 1 .. cols.count loop
new_cols(i) := dbms_tf.column_metadata_t (
name => cols(i),
type => dbms_tf.type_number
);
end loop;
return dbms_tf.describe_t ( new_columns => new_cols );
end;
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
To add the new columns to the results, you must return them
using dbms_tf.describe_t
13. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
select * from add_columns (
dual, columns ( c1 )
);
DUMMY C1
X <null>
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
14. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
select * from add_columns (
dual, columns ( c1, c2 )
);
DUMMY C1 C2
X <null> <null>
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
15. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
fetch_rows procedure
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
To assign values to each row for the new columns you need a
fetch_rows procedure
The following fetch_rows body sets the value of new
columns to
row# * column#
16. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
begin
env := dbms_tf.get_env();
for clmn in 1 .. env.ref_put_col.count loop
for rw in 1 .. env.row_count loop
col ( rw ) := rw * clmn;
end loop;
dbms_tf.put_col ( clmn, col );
end loop;
end fetch_rows;
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
dbms_tf.get_env captures the
current execution state
This includes details of all the
rows and columns processed in
this iteration of fetch_rows
17. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
begin
env := dbms_tf.get_env();
for clmn in 1 .. env.ref_put_col.count loop
for rw in 1 .. env.row_count loop
col ( rw ) := rw * clmn;
end loop;
dbms_tf.put_col ( clmn, col );
end loop;
end fetch_rows;
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
col is an array of row values
for a column
18. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
begin
env := dbms_tf.get_env();
for clmn in 1 .. env.ref_put_col.count loop
for rw in 1 .. env.row_count loop
col ( rw ) := rw * clmn;
end loop;
dbms_tf.put_col ( clmn, col );
end loop;
end fetch_rows;
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
To return the row values to the
client, you must call
dbms_tf.put_col
This assigns the array of row
values to the put column at
position CLMN
19. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
select * from add_columns (
tab,
columns ( c1, c2 )
);
X C1 C2
1 1 2
2 2 4
3 3 6
4 4 8
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
tab is a four-row table with the
column x
The PTF assigns incrementing
values to the columns added
20. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
select * from add_columns (
tab,
columns ( c1, c2 )
);
X C1 C2
1 1 2
2 2 4
3 3 6
4 4 8
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
21. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
select * from add_columns (
tab order by x desc,
columns ( c1, c2 )
);
X C1 C2
4 1 2
3 2 4
2 3 6
1 4 8
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
This PTF uses table semantics
So you can sort the input with
an order by clause after the
table name
This has a descending sort, so as
X decreases, C1 increases
22. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
select * from add_columns (
tab partition by y order by x desc,
columns ( c1, c2 )
);
X Y C1 C2
4 0 1 2
2 0 2 4
3 1 1 2
1 1 2 4
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
This PTF uses table semantics
So you can also split the input
into groups with an partition by
clause after the table name
The database calls the
fetch_rows procedure at least
once for each distinct value in
the partition by
Y = mod (X, 2); so odd and even
values of X have separate
counters
23. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
X Y C1 C2
1021 1 1021 2042
1022 0 1022 2044
1023 1 1023 2046
1024 0 1024 2048
1025 1 1 2
1026 0 2 4
1027 1 3 6
1028 0 4 8
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
PTFs process rows in batches
Empirical testing shows this as
units of 1,024 rows (whether
this is a hard limit is TBC)
After fetching this many rows,
the PTF calls fetch_rows again
So this resets the counter
If you write PTFs which have
running counters or
aggregations, you'll need to
save the execution state
You can do this with
dbms_tf.xstore procedures
24. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
for clmn in 1 .. env.ref_put_col.count loop
dbms_tf.xstore_get('col' || clmn, last_row);
for rw in 1 .. env.row_count loop
col ( rw ) := ( rw + last_row ) * clmn;
end loop;
dbms_tf.put_col ( clmn, col );
dbms_tf.xstore_set (
'col' || clmn, last_row + env.row_count
);
end loop;
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
The xstore holds key-
value pairs
If you get a non-
existent key, the input
value is unchanged
25. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
How do
I debug it?
Gratisography
26. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
dbms_tf.trace (
env => dbms_tf.get_env()
);
dbms_tf.trace (
msg => 'Your text here'
);
blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
The dbms_tf.trace procedure
has several overloads which
allow you to view the current
execution state
In my experience, the most
useful are:
• env; this displays the whole
execution state
• msg; which allows you to
add your own text
Like dbms_output, tracing
displays the results on screen,
not in a database table or view
27. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
Now it's over to you!
Where canYou can find many PTF examples on https://livesql.oracle.com
28. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
asktom.oracle.com
#AskTOMOfficeHours
Ryan McGuire / Gratisography