SELECT XMLELEMENT( "customer", XMLELEMENT("customer_id", customer_id), XMLELEMENT("name", first_name ||' '|| last_name) ).GETSTRINGVAL() AS xml_customers FROM customers WHERE customer_id IN (1, 2);
SELECT XMLELEMENT( "customer", XMLATTRIBUTES( customer_id AS "id", first_name ||' '|| last_name AS "name", TO_CHAR(dob, 'MM/DD/YYYY') AS "dob" ) ).GETSTRINGVAL() AS xml_customers FROM customers WHERE customer_id IN (1, 2);
SELECT XMLELEMENT( "customer", XMLFOREST( customer_id AS "id", first_name ||' '|| last_name AS "name", TO_CHAR(dob, 'MM/DD/YYYY') AS "dob", ''AS'empty' ) ).GETSTRINGVAL() AS xml_customers FROM customers WHERE customer_id IN (1, 2);
SELECT XMLELEMENT( "customer", XMLCOLATTVAL( customer_id AS "id", dob as "dob" ) ).GETSTRINGVAL() AS xml_customers FROM customers WHERE customer_id in (1, 2);
XML_CUSTOMERS
<customer><column name = "id">1</column><column name = "dob">1965-01-01</column></customer>
<customer><column name = "id">2</column><column name = "dob">1968-02-05</column></customer>
SELECT XMLCONCAT( XMLELEMENT("name", first_name ||' '|| last_name), XMLELEMENT("phone", phone) ).GETSTRINGVAL() AS xml_customers FROM customers WHERE customer_id in (1, 2);
SELECT XMLELEMENT( "customer", XMLELEMENT("customer_id", customer_id), XMLELEMENT("name", XMLCDATA(first_name ||' '|| last_name)) ).GETSTRINGVAL() AS xml_customers FROM customers WHERE customer_id IN (1, 2);
SELECTextract(value(d), '//EMPNO/text()').getNumberVal() AS empno, extract(value(d), '//ENAME/text()').getStringVal() AS ename, extract(value(d), '//JOB/text()').getStringVal() AS job, extract(value(d), '//MGR/text()').getNumberVal() AS mgr, extract(value(d), '//HIREDATE/text()').getStringVal() AS hiredate, extract(value(d), '//SAL/text()').getNumberVal() AS sal FROM xml_tab x, table(xmlsequence(extract(value(x), '/ROWSET/EMP'))) d;
SELECT XMLQUERY( 'for $product in doc("/public/products.xml")/products/product let $product_type := doc("/public/product_types.xml")//product_type[@product_type_id = $product/@product_type_id]/@name where $product/@price > 20 order by $product/@product_id return <product name="{$product/@name}" product_type="{$product_type}"/>' RETURNING CONTENT ).GETSTRINGVAL() AS xml_query_results FROM dual;
Adding the XML keyword to the PIVOT operator allows us to convert the generated pivot results to XML format. It also makes the PIVOT a little more flexible, allowing us to replace the hard coded IN clause with a subquery, or the ANY wildcard.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
createtable pivot_test ( id number, customer_id number, product_code varchar2(5), quantity number );
select* from (select product_code, quantity from pivot_test) pivot xml (sum(quantity) as sum_quantity for (product_code) in (selectdistinct product_code from pivot_test where id <10));
-- create the types CREATE TYPE t_product AS OBJECT ( product_id INTEGER, name VARCHAR2(15), quantity INTEGER ); /
CREATE TYPE t_nested_table_product ASTABLEOF t_product; /
-- create the table CREATETABLE purchase_order ( purchase_order_id INTEGERCONSTRAINT purchase_order_pk PRIMARY KEY, customer_order_id INTEGER, order_date DATE, customer_name VARCHAR2(25), street VARCHAR2(15), city VARCHAR2(15), state VARCHAR2(2), zip VARCHAR2(5), phone_number VARCHAR2(12), products t_nested_table_product, xml_purchase_order XMLType ) NESTED TABLE products STORE AS nested_products;
-- create the directory (you may need to modify this line) -- then copy purchase_order.xml to the directory and grant permission `chmod '/usr/tmp/edi/purchase_order.xml' 777` CREATEOR REPLACE DIRECTORY XML_FILES_DIR AS'/usr/tmp/edi'; SELECT*FROM ALL_DIRECTORIES WHERE DIRECTORY_NAME ='XML_FILES_DIR';
-- add a row to the table INSERTINTO purchase_order ( purchase_order_id, xml_purchase_order ) VALUES ( 1, XMLType( BFILENAME('XML_FILES_DIR', 'purchase_order.xml'), -- 指向外部文件的指针 NLS_CHARSET_ID('AL32UTF8') -- 标准 UTF-8 编码 ) );
SELECT EXTRACT(xml_purchase_order, '/purchase_order/products/product[2]').GETSTRINGVAL() xml_product FROM purchase_order WHERE purchase_order_id =1;
检索 “Supernova video” 产品。
1 2 3 4
SELECT EXTRACT(xml_purchase_order, '/purchase_order/products/product[name="Supernova video"]').GETSTRINGVAL() xml_product FROM purchase_order WHERE purchase_order_id =1;
SELECT'EXISTS' FROM purchase_order WHERE purchase_order_id =1 AND EXISTSNODE( xml_purchase_order, '/purchase_order/products/product[product_id=1]') =1;
--EXISTS
XMLSEQUENCE 将产品检索为 XMLType 对象的变长数组
1 2 3 4 5 6
SELECT product.column_value--.GETSTRINGVAL() FROMTABLE( SELECT XMLSEQUENCE(EXTRACT(xml_purchase_order, '/purchase_order//product')) FROM purchase_order WHERE purchase_order_id =1) product;
PRODUCT.COLUMN_VALUE
<XMLTYPE>
<XMLTYPE>
使用 EXTRACTVALUE () 函数将产品的 product_id, name 和 quantity 检索为字符串。
1 2 3 4 5 6 7 8 9
SELECT EXTRACTVALUE(product.column_value, '/product/product_id') AS product_id, EXTRACTVALUE(product.column_value, '/product/name') AS name, EXTRACTVALUE(product.column_value, '/product/quantity') AS quantity FROMTABLE( SELECT XMLSEQUENCE(EXTRACT(xml_purchase_order, '/purchase_order//product')) FROM purchase_order WHERE purchase_order_id =1) product;
CREATEPROCEDURE update_purchase_order( p_purchase_order_id IN purchase_order.purchase_order_id%TYPE ) AS v_count INTEGER :=1;
-- declare a nested table to store products v_nested_table_products t_nested_table_product := t_nested_table_product();
-- declare a type to represent a product record TYPE t_product_record IS RECORD ( product_id INTEGER, name VARCHAR2(15), quantity INTEGER );
-- declare a REF CURSOR type to point to product records TYPE t_product_cursor ISREFCURSORRETURN t_product_record;
-- declare a cursor v_product_cursor t_product_cursor;
-- declare a variable to store a product record v_product t_product_record; BEGIN -- open v_product_cursor to read the product_id, name, and quantity for -- each product stored in the XML of the xml_purchase_order column -- in the purchase_order table OPEN v_product_cursor FOR SELECT EXTRACTVALUE(product.COLUMN_VALUE, '/product/product_id') AS product_id, EXTRACTVALUE(product.COLUMN_VALUE, '/product/name') AS name, EXTRACTVALUE(product.COLUMN_VALUE, '/product/quantity') AS quantity FROMTABLE( SELECT XMLSEQUENCE(EXTRACT(xml_purchase_order, '/purchase_order//product')) FROM purchase_order WHERE purchase_order_id = p_purchase_order_id ) product;
-- loop over the contents of v_product_cursor LOOP -- fetch the product records from v_product_cursor and exit when there -- are no more records found FETCH v_product_cursor INTO v_product; EXIT WHEN v_product_cursor%NOTFOUND;
-- extend v_nested_table_products so that a product can be stored in it v_nested_table_products.EXTEND;
-- create a new product and store it in v_nested_table_products v_nested_table_products(v_count) := t_product(v_product.product_id, v_product.name, v_product.quantity);
-- display the new product stored in v_nested_table_products DBMS_OUTPUT.PUT_LINE('product_id = '|| v_nested_table_products(v_count).product_id); DBMS_OUTPUT.PUT_LINE('name = '|| v_nested_table_products(v_count).name); DBMS_OUTPUT.PUT_LINE('quantity = '|| v_nested_table_products(v_count).quantity);
-- increment v_count ready for the next iteration of the loop v_count := v_count +1; END LOOP;
-- close v_product_cursor CLOSE v_product_cursor;
-- update the purchase_order table using the values extracted from the -- XML stored in the xml_purchase_order column (the products nested -- table is set to v_nested_table_products already populated by the -- previous loop) UPDATE purchase_order SET customer_order_id = EXTRACTVALUE(xml_purchase_order, '/purchase_order/customer_order_id'), order_date = TO_DATE(EXTRACTVALUE(xml_purchase_order, '/purchase_order/order_date'), 'YYYY-MM-DD'), customer_name = EXTRACTVALUE(xml_purchase_order, '/purchase_order/customer_name'), street = EXTRACTVALUE(xml_purchase_order, '/purchase_order/street'), city = EXTRACTVALUE(xml_purchase_order, '/purchase_order/city'), state = EXTRACTVALUE(xml_purchase_order, '/purchase_order/state'), zip = EXTRACTVALUE(xml_purchase_order, '/purchase_order/zip'), phone_number = EXTRACTVALUE(xml_purchase_order, '/purchase_order/phone_number'), products = v_nested_table_products WHERE purchase_order_id = p_purchase_order_id;
-- commit the transaction COMMIT; END update_purchase_order; /
select yeh.po_number, XMLELEMENT("table", XMLCONCAT( XMLELEMENT("tr", XMLELEMENT("th", 'EDI Type'), XMLELEMENT("th", 'PO Number'), XMLELEMENT("th", 'PO Release Number'), XMLELEMENT("th", 'PO Date'), XMLELEMENT("th", 'Ship to Code'), XMLELEMENT("th", 'Ship to Name'), XMLELEMENT("th", 'Sold to Code'), XMLELEMENT("th", 'Sold to Name') ), XMLAGG( XMLELEMENT("tr", XMLELEMENT("td", yeh.edi_type), XMLELEMENT("td", yeh.po_number), XMLELEMENT("td", yeh.po_release_number), XMLELEMENT("td", yeh.po_date), XMLELEMENT("td", yea_ship.code), XMLELEMENT("td", yea_ship.name), XMLELEMENT("td", yea_sold.code), XMLELEMENT("td", yea_sold.name) ) ) ) ).getStringVal() as table_str from ysc_edi_inbound_header yeh, ysc_edi_inbound_address yea_ship, ysc_edi_inbound_address yea_sold where yeh.header_id = yea_ship.header_id and yeh.header_id = yea_sold.header_id and yea_ship.identifier_code ='ST' and yea_sold.identifier_code ='BY' and yeh.header_id =1 groupby yeh.po_number;
PO_NUMBER
TABLE_STR
2211100025
<table><tr><th>EDI Type</th><th>PO Number</th><th>PO Release Number</th><th>PO Date</th><th>Ship to Code</th><th>Ship to Name</th><th>Sold to Code</th><th>Sold to Name</th></tr><tr><td>855</td><td>2211100025</td><td></td><td>20211130</td><td>147</td><td>XXX TECHNOLOGIES</td><td>84</td><td>XXX TECHNOLOGIES</td></tr></table>
select item.* from som_edi_customer_source ses, xmltable( '/Pip3A4PurchaseOrderRequest/PurchaseOrder/ProductLineItem' passing xmltype(ses.memo) --memo type is clob, if memo is xmltype can direct use passing ses.memo columns cust_name varchar2(1000) path 'CustomerInformation/businessName', cust_po_number varchar2(1000) path 'PartnerBusiness/BusinessIdentifier' ) item where ses.seq_id = p_seq_id;
解决方法 1:添加 xmlnamespace
1 2 3 4 5 6 7 8 9 10 11 12
select item.* from som_edi_customer_source ses, xmltable( --xmlnamespaces('http://schemas.microsoft.com/xxx.dtd' as "ns"), xmlnamespaces(default'http://schemas.microsoft.com/xxx.dtd'), '/Pip3A4PurchaseOrderRequest/PurchaseOrder/ProductLineItem' passing xmltype(ses.memo) columns cust_name varchar2(1000) path'CustomerInformation/businessName', cust_po_number varchar2(1000) path 'PartnerBusiness/BusinessIdentifier' ) item where ses.seq_id = p_seq_id;
解决方法 2: 解析前先移除 namespace
1 2 3 4 5 6 7 8 9 10 11 12 13 14
function remove_namespace(p_xml_clob clob) returnclobis l_return clob; l_taiwan_namespace varchar2(100) :='xmlns="http://schemas.microsoft.com/xxx.dtd"'; l_china_namespace varchar2(100) :='xmlns="http://schemas.microsoft.com/yyy.dtd"'; begin begin select replace(replace(p_xml_clob, l_china_namespace, null), l_taiwan_namespace, null) into l_return from dual; end; return l_return; end remove_namespace;
1 2 3 4 5 6 7 8 9 10 11
select item.* from (select seq_id, remove_namespace(memo) as memo from som_edi_customer_source) ses, xmltable( '/Pip3A4PurchaseOrderRequest/PurchaseOrder/ProductLineItem' passing xmltype(ses.memo) columns cust_name varchar2(1000) path'CustomerInformation/businessName', cust_po_number varchar2(1000) path 'PartnerBusiness/BusinessIdentifier' ) item where ses.seq_id = p_seq_id;
Working with XMLTYPE — cx_Oracle 8.3.0-dev documentation
Oracle XMLType columns are fetched as strings by default. This is currently limited to the maximum length of a VARCHAR2 column. To return longer XML values, they must be queried as LOB values instead.
The examples below demonstrate using XMLType data with cx_Oracle. The following table will be used in these examples:
1 2 3 4
CREATETABLE xml_table ( id NUMBER, xml_data SYS.XMLTYPE );
Inserting into the table can be done by simply binding a string as shown:
This approach works with XML strings up to 1 GB in size. For longer strings, a temporary CLOB must be created using Connection.createlob() and bound as shown:
Fetching XML data can be done simply for values that are shorter than the length of a VARCHAR2 column, as shown:
1 2 3
cursor.execute("select xml_data from xml_table where id = :id", id=1) xml_data, = cursor.fetchone() print(xml_data) # will print the string that was originally stored
For values that exceed the length of a VARCHAR2 column, a CLOB must be returned instead by using the function XMLTYPE.GETCLOBVAL() as shown:
1 2 3 4 5 6
cursor.execute(""" select xmltype.getclobval(xml_data) from xml_table where id = :id""", id=1) clob, = cursor.fetchone() print(clob.read())
The LOB that is returned can be streamed or a string can be returned instead of a CLOB. See Using CLOB and BLOB Data for more information about processing LOBs.