ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

SQL/XML - Creation

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • SQL/XML - Creation

    PHP Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <SI>
    <ORG>AAA</ORG>
    <STORE_GROUP>bbb</STORE_GROUP>
    <SEG5>
    <STORE>88888</STORE>
    <GL_LOCATION>1111</GL_LOCATION>
    <CLOSE_DATE>
    <DATE>2018-12-03 17:02:29</DATE>
    <SEG6>
    <ACCOUNT>1030</ACCOUNT>
    <FOP>11</FOP>
    <SALE_TYPE>NON-ROA</SALE_TYPE>
    <AMOUNT>211.12</AMOUNT>
    </SEG6>
    <SEG6>
    <ACCOUNT>2260</ACCOUNT>
    <FOP>11</FOP>
    <SALE_TYPE>NON-ROA</SALE_TYPE>
    <AMOUNT>-49.53</AMOUNT>
    </SEG6>

    </CLOSE_DATE>
    </SEG5>

    <SEG5>
    <STORE>99999</STORE>
    <GL_LOCATION>6666</GL_LOCATION>
    <CLOSE_DATE>
    <DATE>2018-12-03 17:02:16</DATE>
    <SEG6>
    <ACCOUNT>1030</ACCOUNT>
    <FOP>12</FOP>
    <SALE_TYPE>NON-ROA</SALE_TYPE>
    <AMOUNT>1396.58</AMOUNT>
    </SEG6>
    <SEG6>
    <ACCOUNT>2260</ACCOUNT>
    <FOP>12</FOP>
    <SALE_TYPE>NON-ROA</SALE_TYPE>
    <AMOUNT>-29.77</AMOUNT>
    </SEG6>
    </CLOSE_DATE>
    </SEG5>
    </SI>
    Table looks like
    ~~~~~~~~~~~~
    PHP Code:
    AAA bbb 88888 1111 2018-12-03 17:02:29 1030 11 NON-ROA 211.12
    AAA bbb 88888 1111 2018
    -12-03 17:02:29 2260 11 NON-ROA -49.53
    AAA bbb 99999 6666 2018
    -12-03 17:02:16 1030 12 NON-ROA 211.12
    AAA bbb 99999 6666 2018
    -12-03 17:02:16 2260 12 NON-ROA -29.77 
    Need your help to generate SQL XML query for the above XML.
    Last edited by jamief; January 17, 2019, 02:37 PM.
    Regards,
    Vinothkumar S.

  • #2
    I don't follow. Do you want to take XML and insert it into the table, or take the table and output it as XML?


    If the former, here is a primer on using the XMLTABLE() DB2 SQL function to present XML data (in an XML data type column/var) as relational data for querying or inserting into tables


    If the latter, here is a primer on the XML build DB2 SQL functions for generating XML from relational data
    IBM Developer is your one-stop location for getting hands-on training and learning in-demand skills on relevant technologies such as generative AI, data science, AI, and open source.

    Comment


    • #3
      Hi Vector, i am trying to generate XML build using DB2 SQL. I am struck due to multiple nested elements.
      Regards,
      Vinothkumar S.

      Comment


      • #4
        Well that nearly broke my brain. But here is how I did it, with a step by step explanation:
        Code:
        -- I am using a CTE to create dummy table MYDATA, as the source data
          with mydata as (
        select * from
            (values('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '1030', '11', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '2260', '11', 'NON-ROA', -49.53),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '1030', '12', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '2260', '12', 'NON-ROA', -29.77)
             ) z (org,store_group,store,gl_location,close_date,close_time,account,fop,sale_type,amount))
        select * from mydata;
        
        
        ----------------------------------------
        -- Now let's start by generating the SEG6 XML for every record
        -- This will return 4 records, each record including the SEG6 xml for that record
          with mydata as (
        select * from
            (values('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '1030', '11', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '2260', '11', 'NON-ROA', -49.53),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '1030', '12', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '2260', '12', 'NON-ROA', -29.77)
             ) z (org,store_group,store,gl_location,close_date,close_time,account,fop,sale_type,amount))
        
        select org,store_group,store,gl_location,close_date,close_time,
               xmlelement(name "SEG6",
                       xmlelement(name "ACCOUNT",account),
                       xmlelement(name "FOP",fop),
                       xmlelement(name "SALE_TYPE",sale_type),
                       xmlelement(name "AMOUNT",amount)
               ) as seg6
          from mydata f;
        
        
        ----------------------------------------
        -- Now we need to "aggregate" the SEG6 records - to group them together into a list of SEG6 tags, for every store/gl_location/date/time
        -- Aggregation, with XMLAGG, works like any SQL aggregate function, like count() or max(). You use the group by clause to determine the grouping
        -- The Seg6 column should contain the XML for two SEG6 XML elements
        -- Note that you can specify an order by for an XMLAGG
        -- This will return 2 records, one for each unique combination of org,store_group,store,gl_location,close_date,close_time
        -- Each includes a column containing a list of all the SEG6's for that combo. Should be two in each
          with mydata as (
        select * from
            (values('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '1030', '11', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '2260', '11', 'NON-ROA', -49.53),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '1030', '12', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '2260', '12', 'NON-ROA', -29.77)
             ) z (org,store_group,store,gl_location,close_date,close_time,account,fop,sale_type,amount))
        
        select org,store_group,store,gl_location,close_date,close_time,
                xmlagg(
                   xmlelement(name "SEG6",
                           xmlelement(name "ACCOUNT",account),
                           xmlelement(name "FOP",fop),
                           xmlelement(name "SALE_TYPE",sale_type),
                           xmlelement(name "AMOUNT",amount)
                   )
                   order by account, fop, sale_type, amount
                ) as seg6
          from mydata f
         group by org,store_group,store,gl_location,close_date,close_time;
        
        
        ----------------------------------------
        -- Now we may as well add in the XML for SEG5, to wrap each reord's SEG6 list. And add in STORE, GL_LOCATION, and CLOSE_DATE
        -- I have kept store and gl_loaction as separate output fields for later use (order of a later xmlagg)
        -- This will return 2 records, one for each unique combination of org,store_group,store,gl_location,close_date,close_time
        -- Each includes a column containing the SEG5 XML for that combo (which contains a list of all the SEG6's for that combo)
          with mydata as (
        select * from
            (values('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '1030', '11', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '2260', '11', 'NON-ROA', -49.53),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '1030', '12', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '2260', '12', 'NON-ROA', -29.77)
             ) z (org,store_group,store,gl_location,close_date,close_time,account,fop,sale_type,amount))
        
        select org,store_group,store,gl_location,
                    xmlelement(name "SEG5",
                       xmlelement(name "STORE",store),
                       xmlelement(name "GL_LOCATION",gl_location),
                       xmlelement(name "CLOSE_DATE",
                          xmlelement(name "DATE",close_date || ' ' || close_time),
                          xmlagg(xmlelement(name "SEG6",
                                   xmlelement(name "ACCOUNT",account),
                                   xmlelement(name "FOP",fop),
                                   xmlelement(name "SALE_TYPE",sale_type),
                                   xmlelement(name "AMOUNT",amount)
                                ) order by account, fop, sale_type, amount)
                       )
                    ) as seg5
          from mydata f
         group by org,store_group,store,gl_location,close_date,close_time;
        
        
        ----------------------------------------
        -- Now the next logical step would be to aggregate again, to group the two SEG5's per ORG/STORE_GROUP
        -- But you cannot have to aggregation levels in a single select.
        -- So instead, let's wrap it in a subselect first
        -- Other than that, this will return identical to the previous
          with mydata as (
        select * from
            (values('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '1030', '11', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '2260', '11', 'NON-ROA', -49.53),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '1030', '12', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '2260', '12', 'NON-ROA', -29.77)
             ) z (org,store_group,store,gl_location,close_date,close_time,account,fop,sale_type,amount))
        
        select * from table(
            select org,store_group,store,gl_location,
                        xmlelement(name "SEG5",
                           xmlelement(name "STORE",store),
                           xmlelement(name "GL_LOCATION",gl_location),
                           xmlelement(name "CLOSE_DATE",
                              xmlelement(name "DATE",close_date || ' ' || close_time),
                              xmlagg(xmlelement(name "SEG6",
                                       xmlelement(name "ACCOUNT",account),
                                       xmlelement(name "FOP",fop),
                                       xmlelement(name "SALE_TYPE",sale_type),
                                       xmlelement(name "AMOUNT",amount)
                                    ) order by account, fop, sale_type, amount)
                           )
                        ) as seg5
              from mydata f
             group by org,store_group,store,gl_location,close_date,close_time
            ) as seg5Table
         ;
        
        
        ----------------------------------------
        -- And now, finally, we can aggregate the SEG5 xml to get one XML per ORG/STORE_GROUP
        -- We will add in the SI top level wrapper and ORG/STORE_GROUP tags at the same time
        -- This will complete the XML
        -- note this returns the xml as the XML data type. You would have to wrap in in xmlserialize() if you want the string.
        -- if you use Run SQL Scripts from iACS then the query output will display the string value for you.
          with mydata as (
        select * from
            (values('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '1030', '11', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '88888', '1111', '2018-12-03', '17:02:29', '2260', '11', 'NON-ROA', -49.53),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '1030', '12', 'NON-ROA', 211.12),
                   ('AAA', 'bbb', '99999', '6666', '2018-12-03', '17:02:16', '2260', '12', 'NON-ROA', -29.77)
             ) z (org,store_group,store,gl_location,close_date,close_time,account,fop,sale_type,amount))
        
        select xmlelement(name "SI",
                    xmlelement(name "ORG",org),
                    xmlelement(name "STORE_GROUP",store_group),
                    xmlagg(seg5 order by store,gl_location))
          from table(
            select org,store_group,store,gl_location,
                        xmlelement(name "SEG5",
                           xmlelement(name "STORE",store),
                           xmlelement(name "GL_LOCATION",gl_location),
                           xmlelement(name "CLOSE_DATE",
                              xmlelement(name "DATE",close_date || ' ' || close_time),
                              xmlagg(xmlelement(name "SEG6",
                                       xmlelement(name "ACCOUNT",account),
                                       xmlelement(name "FOP",fop),
                                       xmlelement(name "SALE_TYPE",sale_type),
                                       xmlelement(name "AMOUNT",amount)
                                    ) order by account, fop, sale_type, amount)
                           )
                        ) as seg5
              from mydata f
             group by org,store_group,store,gl_location,close_date,close_time
            ) as seg5Table
         group by org,store_group
         ;

        Comment


        • #5
          Thanks a lot vector. I learned it. Good Explanation.
          Regards,
          Vinothkumar S.

          Comment


          • #6
            In general is there any size limit to the XML document. How many rows i can use to populate this kind of data?
            Regards,
            Vinothkumar S.

            Comment


            • #7
              If you are writing the result into a RPG XML_CLOB Field the maximum is 16MB (RPG Restriction).
              If you are writing the result (with SQL) directly into the IFS (output into a file reference variable XML_CLOB_FILE) the maximum is 2GB

              Birgitta

              Comment


              • #8
                And I assume, if you are writing it to a regular char or varchar, it would be 32k unless you use teraspace?

                What is the maximum size of an XML column in a DB2 table, I wonder?

                Comment


                • #9
                  Originally posted by Vectorspace View Post
                  And I assume, if you are writing it to a regular char or varchar, it would be 32k unless you use teraspace?

                  What is the maximum size of an XML column in a DB2 table, I wonder?
                  If you define your receiver variable as VARCHAR or CHAR in RPG the maximum is 32 K (SQL restriction for CHAR and VARCHAR Columns/Variable - larger SQL variables must be defined as Large Object - CLOB, BLOB, DBCLOB)
                  If you define your receiver variable as SQLTYPE(XML_CLOB: Length) the maximum length is 16MB (RPG Restriction for Variables).
                  SQL does not handle pointers, so a pointer cannot be used and it is not possible to profit from the TeraSpace.
                  If you define your receiver variable as Locator (kind of pointer in SQL) SQLTYPE(XML_CLOB_LOCATOR) or File Reference Variable SQLTYPE(XML_FILE) the maximum length is 2 GB.
                  The maximum length for an XML column, i.e. for the XML data type is 2 GB.

                  Birgitta

                  Comment

                  Working...
                  X