2

我有以下表格:

CREATE TABLE DBO.FACT_SERVICES (
    SVC_ID              INTEGER             NOT NULL,
    SVC_NAME            VARCHAR(50)         NOT NULL,
    SVC_DESC            VARCHAR(2000)       NULL,
    STATUS              VARCHAR(50)         NULL
);

CREATE TABLE DBO.FACT_TYPES (
    FACT_ID             INTEGER             NOT NULL,
    FACT_NAME           VARCHAR(100)        NOT NULL,
    FACT_DESC           VARCHAR(2000)       NULL,
    PARENT_FACT_ID      INTEGER             NULL,
);

CREATE TABLE DBO.FACT_TYPE_SVC (
    FACT_ID             INTEGER             NOT NULL,
    SVC_ID              INTEGER             NOT NULL,
    STATUS              VARCHAR(50)         NULL
);

我创建了以下查询来获取 XML 层次结构:

SELECT
  XMLElement("services", 
    XMLAgg(
      XMLElement("service",
        XMLAttributes(svc.svc_id as "id", svc.svc_name as "name"),
        XMLElement("facts",
          (SELECT
          XMLAgg(
            XMLElement("fact", 
              XMLAttributes(FT.FACT_ID as "id", FT.FACT_NAME AS "name"),
              (SELECT
                XMLAgg(
                  XMLElement("fact",   
                    XMLAttributes(FT2.FACT_ID as "id", FT2.FACT_NAME as "name")
                  )
                )
                FROM
                  DBO.FACT_TYPES FT2 
                WHERE
                  FT2.PARENT_FACT_ID = FT.FACT_ID
              )                             
            )
          )
          FROM
            DBO.FACT_TYPES FT 
            INNER JOIN DBO.FACT_TYPE_SVC FTS ON FTS.FACT_ID = FT.FACT_ID
          WHERE
            FTS.SVC_ID = SVC.SVC_ID AND
            LOWER(FTS.STATUS) = 'active' AND
            PARENT_FACT_ID IS NULL
          )
        )
      )
    )
  )
FROM
  DBO.FACT_SERVICES SVC

这将创建以下 XML:

<services>
    <service id="1" name="ABC Plan">
        <facts>
            <fact id="77" name="Basic Service">
                <fact id="71" name="Form XYZ Schedules"></fact>
                <fact id="101" name="Per Participant Fee"></fact>
                <fact id="103" name="Base Fee"></fact>
            </fact>
        </facts>
    </service>
</services>

但是,我想编写查询,以便我可以拥有 FACT_TYPE 的无限子级。我正在使用 Oracle 中的 dbms_xmlgen.getXmlType(dbms_xmlgen.newContextFromHierarchy()) 函数,但我似乎无法让它与服务部分一起使用。我可以让它直接从 DBO.FACT_TYPES 表中工作,如下所示:

SELECT 
  XMLElement("facts",
  (select dbms_xmlgen.getXmlType(dbms_xmlgen.newContextFromHierarchy('
        select level, 
                XMLElement("fact", 
                  XMLAttributes(ft.fact_id as "id", ft.fact_name as "name")
                )
        from
          dbo.fact_types ft
        start with parent_fact_id is null
        connect by prior fact_id = parent_fact_id
        order siblings by fact_name
  ')) from SYS.DUAL
  )
)AS XML_DATA 
FROM
  SYS.DUAL

返回:

<facts>
    <fact id="77" name="Basic Administrative Service">
        <fact id="103" name="Base Fee"/>
        <fact id="71" name="Form 5500+ Schedules"/>
        <fact id="101" name="Per Participant Fee"/>
    </fact>
</facts>

因此,我尝试创建一个传入服务 ID 的函数,它返回应该进入服务层次结构的内部 XML:

功能

create or replace
FUNCTION     dbo.FACT_GET_FACTS_XML(SERVICE_ID INT) 
RETURN XMLTYPE AS
INNER_SELECT DBMS_XMLGEN.ctxhandle;
MY_RESULT XMLTYPE;
BEGIN
INNER_SELECT := DBMS_XMLGEN.newcontextfromhierarchy(
        'select level, 
            XMLElement("fact", 
              XMLAttributes(ft.fact_id as "id", ft.fact_name as "name")
            )
          from
            dbo.fact_types ft
            inner join dbo.fact_type_svc fts on fts.fact_id = ft.fact_id
          where 
            fts.svc_id = ' || to_char(SERVICE_ID) || ' 
          start with ft.parent_fact_id is null
          connect by prior ft.fact_id = ft.parent_fact_id
          order siblings by ft.fact_name');

MY_RESULT := DBMS_XMLGEN.getxmltype(INNER_SELECT);
DBMS_XMLGEN.closeContext(INNER_SELECT);

RETURN MY_RESULT;

END;

使用此父查询:

SELECT 
  XMLElement("services", 
    XMLAgg(
      XMLElement("service",
        XMLAttributes(svc.svc_id as "id", svc.svc_name as "name"),
        (SELECT 
          XMLElement("facts",
          DBO.FACT_GET_FACTS_XML(SVC.SVC_ID))
        FROM
          SYS.DUAL)
      )
    )
  )
FROM
  DBO.FACT_SERVICES SVC

现在我得到了这个结果:

<services>
    <service id="1" name="ABC Plan">
        <facts>
            <fact id="77" name="Basic Service">
                <fact id="103" name="Base Fee"/>
                <fact id="71" name="Form XYZ Schedules"/>
                <fact id="101" name="Per Participant Fee"/>
                <fact id="103" name="Base Fee"/>
                <fact id="71" name="Form XYZ Schedules"/>
                <fact id="101" name="Per Participant Fee"/>
            </fact>
        </facts>
    </service>
    <service id="4" name="Health Retirement Account">
        <facts>
            <fact id="71" name="Form XYZ Schedules"/>
            <fact id="71" name="Form XYZ Schedules"/>
        </facts>
    </service>
</services>

我想要的 XML 如下:

<services>
    <service id="1" name="ABC Plan">
        <facts>
            <fact id="77" name="Basic Service">
                <fact id="71" name="Form XYZ Schedules"></fact>
                <fact id="101" name="Per Participant Fee"></fact>
                <fact id="103" name="Base Fee"></fact>
            </fact>
        </facts>
    </service>
    <service id="4" name="Health Retirement Account">
      <facts></facts>
    </service>
</services>

但是能够将孩子添加到 fact id="71" 并让它显示在下面。

编辑 这是我目前在表格中的数据

INSERT INTO DBO.FACT_TYPES (FACT_ID, FACT_NAME, FACT_DESC, PARENT_FACT_ID) VALUES (71, 'Form 5500+ Schedules', '', 77);
INSERT INTO DBO.FACT_TYPES (FACT_ID, FACT_NAME, FACT_DESC, PARENT_FACT_ID) VALUES (77, 'Basic Administrative Service', 'Master Group', );
INSERT INTO DBO.FACT_TYPES (FACT_ID, FACT_NAME, FACT_DESC, PARENT_FACT_ID) VALUES (101, 'Per Participant Fee', '', 77);
INSERT INTO DBO.FACT_TYPES (FACT_ID, FACT_NAME, FACT_DESC, PARENT_FACT_ID) VALUES (103, 'Base Fee', '', 77);

INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (77, 1, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (77, 3, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (71, 1, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (71, 3, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (71, 4, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (101, 1, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (101, 3, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (101, 21, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (103, 1, 'ACTIVE');
INSERT INTO DBO.FACT_TYPE_SVC (FACT_ID, SVC_ID, STATUS) VALUES (103, 3, 'ACTIVE');

INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (1, '401(k) Plan', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (4, 'Health Retirement Account', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (5, 'Profit Sharing Plan', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (2, 'Plan Money Purchase', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (3, '403(b) Plan', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (21, 'ESOP Plan', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (22, 'Health Savings Account', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (23, '457 Plan', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (24, 'Simple Plan ', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (25, '503c Plan', '', 'Active');
INSERT INTO DBO.FACT_SERVICES (SVC_ID, SVC_NAME, SVC_DESC, STATUS) VALUES (26, 'Cafeteria Plan', '', 'Active');
4

2 回答 2

2

我想你想要的可能就是这个?

select XMLElement("services",
           XMLAgg(
             XMLElement("service",
               XMLAttributes(svc.svc_id as "id", svc.svc_name as "name"),
              XMLElement("facts",
               (select dbms_xmlgen.getXmlType(dbms_xmlgen.newContextFromHierarchy('
                   select level,
                          XMLElement("fact",
                            XMLAttributes(ft.fact_id as "id", ft.fact_name as "name")
                          )
                    from fact_types ft
                         inner join fact_type_svc fts
                                 on fts.fact_id = ft.fact_id
                   where fts.SVC_ID = ' || svc.svc_id || '
                   start with ft.parent_fact_id is null
                 connect by prior ft.fact_id = ft.parent_fact_id
                   order siblings by ft.fact_name
                      '))
                 from dual
                )
              )
            )
          )
        ) a
   from fact_services svc;

例如,使用一些示例数据(忽略额外的 transform() 部分..我添加它只是为了强制缩进以提高可读性):

SQL> insert into FACT_TYPES
  2  select 77, 'Basic Service', '', null from dual union all
  3  select 101, 'Per Participant Fee', '', 77 from dual union all
  4  select 103, 'Base Fee', '', 77 from dual union all
  5  select 71, 'Form XYZ Schedules', '', null from dual union all
  6  select 72, 'Form XYZ Schedules 2', '', 71 from dual union all
  7  select 200, 'Test', '', 103 from dual  union all
  8  select 201, 'Another child', '', 200 from dual  union all
  9  select 202, 'FooBar', '', 200 from dual;

8 rows created.

SQL> insert into FACT_SERVICES
  2  select 1, 'ABC Plan', '', 'ACTIVE' from dual union all
  3  select 4, 'Health Retirement Account', '', 'ACTIVE' from dual;

2 rows created.

SQL> insert into FACT_TYPE_SVC
  2  select 77, 1, 'ACTIVE' from dual union all
  3  select 101, 1, 'ACTIVE' from dual union all
  4  select 103, 1, 'ACTIVE' from dual union all
  5  select 200, 1, 'ACTIVE' from dual union all
  6  select 201, 1, 'ACTIVE' from dual union all
  7  select 202, 1, 'ACTIVE' from dual union all
  8  select 71, 4, 'ACTIVE' from dual union all
  9  select 72, 4, 'ACTIVE' from dual;

8 rows created.

SQL> commit;

Commit complete.

SQL> select XMLElement("services",
  2             XMLAgg(
  3               XMLElement("service",
  4                 XMLAttributes(svc.svc_id as "id", svc.svc_name as "name"),
  5                XMLElement("facts",
  6                 (select dbms_xmlgen.getXmlType(dbms_xmlgen.newContextFromHierarchy('
  7                     select level,
  8                            XMLElement("fact",
  9                              XMLAttributes(ft.fact_id as "id", ft.fact_name as "name")
 10                            )
 11                      from fact_types ft
 12                           inner join fact_type_svc fts
 13                                   on fts.fact_id = ft.fact_id
 14                     where fts.SVC_ID = ' || svc.svc_id || '
 15                     start with ft.parent_fact_id is null
 16                   connect by prior ft.fact_id = ft.parent_fact_id
 17                     order siblings by ft.fact_name
 18                        '))
 19                   from dual
 20                  )
 21                )
 22              )
 23            )
 24          ).transform(xmltype('<xsl:stylesheet version="1.0"
 25   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 26   <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
 27   <xsl:template match="node()|@*">
 28    <xsl:copy>
 29     <xsl:apply-templates select="node()|@*"/>
 30    </xsl:copy>
 31   </xsl:template>
 32  </xsl:stylesheet>')) a
 33     from fact_services svc;

A
--------------------------------------------------------------------------------

<services>
 <service id="1" name="ABC Plan">
  <facts>
   <fact id="77" name="Basic Service">
    <fact id="103" name="Base Fee">
     <fact id="200" name="Test">
      <fact id="201" name="Another child">
      </fact>
      <fact id="202" name="FooBar">
      </fact>
     </fact>
    </fact>
    <fact id="101" name="Per Participant Fee">
    </fact>
   </fact>
  </facts>
 </service>
 <service id="4" name="Health Retirement Account">
  <facts>
   <fact id="71" name="Form XYZ Schedules">
    <fact id="72" name="Form XYZ Schedules 2">
    </fact>
   </fact>
  </facts>
 </service>
</services>
于 2013-01-14T21:23:09.083 回答
1

在您提供的查询中:

select 
    XMLElement("services",
        XMLAgg(
            XMLElement("service",
                XMLAttributes(svc.svc_id as "id", svc.svc_name as "name"),
                XMLElement("facts",
                    (select dbms_xmlgen.getXmlType(dbms_xmlgen.newContextFromHierarchy('
                        select level,
                            XMLElement("fact",
                                XMLAttributes(ft.fact_id as "id", ft.fact_name as "name")
                            )
                        from 
                            dbo.fact_types ft
                            inner join dbo.fact_type_svc fts on fts.fact_id = ft.fact_id
                        where 
                            fts.SVC_ID = ' || svc.svc_id || '
                        start with ft.parent_fact_id is null
                        connect by prior ft.fact_id = ft.parent_fact_id
                        order siblings by ft.fact_name
                    ')) from sys.dual
                    )
                )
            )
        )
    ) a
from 
    dbo.fact_services svc;

我得到以下结果:

<services>
    <service id="1" name="401(k) Plan">
        <facts>
            <fact id="77" name="Basic Administrative Service">
                <fact id="103" name="Base Fee" />
                <fact id="71" name="Form 5500+ Schedules" />
                <fact id="101" name="Per Participant Fee" />
                <fact id="103" name="Base Fee" />
                <fact id="71" name="Form 5500+ Schedules" />
                <fact id="101" name="Per Participant Fee" />
            </fact>
        </facts>
    </service>
    <service id="4" name="Health Retirement Account">
        <facts>
            <fact id="71" name="Form 5500+ Schedules" />
            <fact id="71" name="Form 5500+ Schedules" />
        </facts>
    </service>
    <service id="5" name="Profit Sharing Plan ">
        <facts />
    </service>
    <service id="2" name="Plan Money Purchase">
        <facts />
    </service>
    <service id="3" name="403(b) Plan">
        <facts>
            <fact id="103" name="Base Fee" />
            <fact id="71" name="Form 5500+ Schedules" />
            <fact id="101" name="Per Participant Fee" />
            <fact id="77" name="Basic Administrative Service">
                <fact id="103" name="Base Fee" />
                <fact id="71" name="Form 5500+ Schedules" />
                <fact id="101" name="Per Participant Fee" />
            </fact>
        </facts>
    </service>
    <service id="21" name="ESOP Plan ">
        <facts>
            <fact id="101" name="Per Participant Fee" />
            <fact id="101" name="Per Participant Fee" />
        </facts>
    </service>
    <service id="22" name="Health Savings Account">
        <facts />
    </service>
    <service id="23" name="457 Plan ">
        <facts />
    </service>
    <service id="24" name="Simple Plan ">
        <facts />
    </service>
    <service id="25" name="503c Plan">
        <facts />
    </service>
    <service id="26" name="Cafeteria Plan ">
        <facts />
    </service>
</services>

但是如果我将移动svc.svc_id到:whereinner join

select 
    XMLElement("services",
        XMLAgg(
            XMLElement("service",
                XMLAttributes(svc.svc_id as "id", svc.svc_name as "name"),
                XMLElement("facts",
                    (select dbms_xmlgen.getXmlType(dbms_xmlgen.newContextFromHierarchy('
                        select level,
                            XMLElement("fact",
                                XMLAttributes(ft.fact_id as "id", ft.fact_name as "name")
                            )
                        from 
                            dbo.fact_types ft
                            inner join dbo.fact_type_svc fts on fts.fact_id = ft.fact_id AND fts.SVC_ID = ' || svc.svc_id || '
                        start with ft.parent_fact_id is null
                        connect by prior ft.fact_id = ft.parent_fact_id
                        order siblings by ft.fact_name
                    ')) from sys.dual
                    )
                )
            )
        )
    ) a
from 
    dbo.fact_services svc;

我得到了正确的 XML 结构:

<services>
    <service id="1" name="401(k) Plan">
        <facts>
            <fact id="77" name="Basic Administrative Service">
                <fact id="103" name="Base Fee" />
                <fact id="71" name="Form 5500+ Schedules" />
                <fact id="101" name="Per Participant Fee" />
            </fact>
        </facts>
    </service>
    <service id="4" name="Health Retirement Account">
        <facts />
    </service>
    <service id="5" name="Profit Sharing Plan ">
        <facts />
    </service>
    <service id="2" name="Plan Money Purchase">
        <facts />
    </service>
    <service id="3" name="403(b) Plan">
        <facts>
            <fact id="77" name="Basic Administrative Service">
                <fact id="103" name="Base Fee" />
                <fact id="71" name="Form 5500+ Schedules" />
                <fact id="101" name="Per Participant Fee" />
            </fact>
        </facts>
    </service>
    <service id="21" name="ESOP Plan ">
        <facts />
    </service>
    <service id="22" name="Health Savings Account">
        <facts />
    </service>
    <service id="23" name="457 Plan ">
        <facts />
    </service>
    <service id="24" name="Simple Plan ">
        <facts />
    </service>
    <service id="25" name="503c Plan">
        <facts />
    </service>
    <service id="26" name="Cafeteria Plan ">
        <facts />
    </service>
</services>

就像 Oracle 在处理完第一个层次结构后忽略了 where 条件。谢谢您的帮助。

于 2013-01-15T15:02:04.410 回答