L oop через связанные таблицы для создания XML файла - PullRequest
0 голосов
/ 10 февраля 2020

У меня есть три таблицы Страна, Провинция, Город, и мне нужно превратить их в формат XML. Вот примерно то, что я ищу, так как у меня есть пример кода, предназначенный для работы с этим форматом.

<Countries>
    <Country>
        <CountryId>1</CountryId><CountryName>Canada</CountryName>
        <Provinces>
            <Province>
                <ProvinceId>1</ProvinceId><ProvinceName>Alberta</ProvinceName>
                <Cities>
                    <CityId>1</CityId><CityName>City 1</CityName>
                    <CityId>2</CityId><CityName>City 2</CityName>
                </Cities>
            </Province>
            <Province>
                <ProvinceId>2</ProvinceId><ProvinceName>Ontario</ProvinceName>
            </Province>
        </Provinces>
    </Country>
    <Country>
        <CountryId>2</CountryId><CountryName>United States of America</CountryName>
        <Provinces>
            <Province>
                <ProvinceId>1</ProvinceId><ProvinceName>Florida</ProvinceName>
            </Province>
        </Provinces>
    </Country>
</Countries>

Страна таблицы

Country_Code
Country_Name

Таблица провинций

Prov_Code
Prov_Name
Country_Code

Table City

City_Id
City_Name
Prov_Code
Country_Code
declare
  thiscountry country_table%rowtype;

  cursor mycountries is select * from country_table where rownum<50;
begin
  --alter buffer size for 10g+
  DBMS_OUTPUT.ENABLE (buffer_size => NULL);
  DBMS_OUTPUT.PUT_LINE ('<Countries>');
  open mycountries;
  loop
    fetch mycountries into thiscountry;
    exit WHEN mycountries%NOTFOUND;

    DBMS_OUTPUT.PUT_LINE ('<Country>');
      DBMS_OUTPUT.PUT_LINE ('<CountryId>' || thiscountry.country_code || '</CountryId>');
      DBMS_OUTPUT.PUT_LINE ('<CountryName>' || thiscountry.country_eng || '</CountryName>');
      DBMS_OUTPUT.PUT_LINE ('<Provinces>');
        declare
          thisprovince province_table%ROWTYPE;
          cursor myprovinces is select * from province_table where country_code=thiscountry.country_code and rownum<5;
        begin
          open myprovinces;
          loop
            fetch myprovinces into thisprovince;
            exit when myprovinces%NOTFOUND;
            DBMS_OUTPUT.PUT_LINE ('<Provience>');
            DBMS_OUTPUT.PUT_LINE ('<ProvienceId>' || thisprovince.prov_code || '</ProvienceId>');
            DBMS_OUTPUT.PUT_LINE ('<ProvienceName>' || thisprovince.prov_eng || '</ProvienceName>');
            DBMS_OUTPUT.PUT_LINE ('<Cities>');  
            declare
              thiscity city_table%ROWTYPE;
              cursor mycities is select * from city_table where city_table.prov_code=thisprovince.prov_code and rownum<5;
            begin
              open mycities;
              loop
                fetch mycities into thiscity;
                DBMS_OUTPUT.PUT_LINE ('<City>');
                DBMS_OUTPUT.PUT_LINE ('<CityID>' || thiscity.city_id || '</CityID>');
                DBMS_OUTPUT.PUT_LINE ('<CityName>' || thiscity.city_en || '</CityName>');
                DBMS_OUTPUT.PUT_LINE ('</City>');
              end loop;
              close mycities;
            end;
            DBMS_OUTPUT.PUT_LINE ('</Cities>');
            DBMS_OUTPUT.PUT_LINE ('<Provience>');
          end loop;
          close myprovinces;
        end;
    DBMS_OUTPUT.PUT_LINE ('</Provinces>');  
    DBMS_OUTPUT.PUT_LINE ('</Country>');
  end loop;
  close mycountries;
  DBMS_OUTPUT.PUT_LINE ('</Countries>');
end;

Когда я запускаю вышеописанное, у меня возникают проблемы с производительностью, и он не работает, потому что не хватает памяти ORA-04030: out of process memory when trying to allocate.

I пошел созданный вид, который будет иметь всю необходимую информацию. Но я подхожу к вопросу о том, как циклически просматривать записи, отображая правильный вывод.

1 Ответ

3 голосов
/ 11 февраля 2020

Существует несколько способов создания такого XML.

. Один из подходов заключается в работе с типами объектов:

CREATE OR REPLACE TYPE "City" AS OBJECT (
 "CityId" NUMBER,
 "CityName" VARCHAR2(100));

CREATE OR REPLACE TYPE "Cities_T" IS TABLE OF "City";

CREATE OR REPLACE TYPE "Province" AS OBJECT (
    "ProvinceId" NUMBER,
    "ProvinceName" VARCHAR2(100),
    "Cities" "Cities_T"
);

CREATE OR REPLACE TYPE "Provinces_T" IS TABLE OF "Province";

CREATE OR REPLACE TYPE "Provinces" AS OBJECT (
    "Provinces" "Provinces_T"
);


SELECT
    XMLTYPE(
        "Province"(
            Prov_Code, 
            Prov_Name, 
            CAST(MULTISET(SELECT city_id, city_name FROM CITY c WHERE c.Prov_Code = p.Prov_Code ORDER BY city_id) AS "Cities_T") 
        ) 
    )
FROM PROVINCE p

Или вы создаете элементы XML более вручную, например это:

SELECT 
    XMLELEMENT("Province", 
        XMLELEMENT("ProvinceId", Prov_Code),
        XMLELEMENT("ProvinceName", Prov_Name),
        XMLELEMENT("Cities", (
            SELECT XMLAGG(
                XMLELEMENT("City", 
                    XMLELEMENT("CityId", city_id), 
                    XMLELEMENT("CityName", city_name)
                ) ORDER BY city_id) 
            FROM CITY c 
            WHERE c.Prov_Code = p.Prov_Code)
        )
    )
FROM PROVINCE p

Я бы порекомендовал создать несколько представлений или таблиц CTE (используя WITH city AS (SELECT ...), тогда окончательное утверждение будет менее сложным, например,

CREATE OR REPLACE VIEW XV_CITY AS
SELECT Prov_Code,
    XMLELEMENT("Cities", 
        XMLAGG(
        XMLELEMENT("City", 
            XMLELEMENT("CityId", city_id), 
            XMLELEMENT("CityName", city_name)
        ) ORDER BY city_id)
    ) AS CITIES_XML
FROM CITY
GROUP BY Prov_Code;

SELECT 
    XMLELEMENT("Province", 
        XMLELEMENT("ProvinceId", Prov_Code),
        XMLELEMENT("ProvinceName", Prov_Name),
        (SELECT CITIES_XML FROM XV_CITY c WHERE c.Prov_Code = p.Prov_Code)      
    )
FROM PROVINCE p

. Другой подход заключается в использовании DBMS_XMLGEN , см. Также Создание XML Использование DBMS_XMLGEN

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...