Postgres JSONb termasuk array ke XML dengan kunci dan nilai dan nilai

Oct 14 2020

Saya memiliki tabel seperti di bawah ini:

id  (VARCHAR) | field1 (text) | attributes  (jsonb)     
--------------+---------------+----------------------------------

 123          |   a           |   {"age": "1", "place": "TX"}                 
 456          |   b           |   {"age": "2", "name": "abcdef"}     
 789          |               |       
 098          |   c           |   {"name": ["abc", "def", "ghi"]}     

Ingin mengubahnya menjadi:

 <Company id="123" field="a">
      <CompanyTag tagName="age" tagValue="1"/>
      <CompanyTag tagName="place" tagValue="TX"/>
 </Company>
 <Company id="456" field="b">
      <CompanyTag tagName="age" tagValue="2"/>
      <CompanyTag tagName="name" tagValue="abcdef"/>
 </Company>
 <Company id="789"/>
  <Company id="098" field="c">
      <CompanyTag tagName="name" tagValue="abc"/>
      <CompanyTag tagName="name" tagValue="def"/>
      <CompanyTag tagName="name" tagValue="ghi"/>
 </Company>

Dengan bantuan @bergi dan @Georges Martin di bawah Post dapat mengonversi non array menggunakan kueri di bawah ini:

SELECT XMLELEMENT(
  NAME "Company", 
  XMLATTRIBUTES(id AS id, field1 AS field), 
  (SELECT XMLAGG(
    XMLELEMENT(
      NAME "companyTag", 
      XMLATTRIBUTES(
        attr.key AS "tagName", 
        attr.value AS "tagValue"
      )
    )
  ) FROM JSONB_EACH_TEXT(attributes) AS attr)
) FROM comp_emp;

Namun nilai array ditampilkan seperti di bawah ini:

 <Company id="098" field="c">
      <CompanyTag tagName="name"tagValue="[&quot;abc&quot;, &quot;def&quot;, &quot;ghi&quot;]"/> 

Saya tidak ingin menyebutkan kunci ("nama tag") secara khusus dalam kueri karena ini mungkin berbeda. Dengan asumsi bahwa ini disebabkan karena JSONB_EACH_TEXT mengekstrak nilai terluar. Apakah ada alternatif lain?

Tolong bimbing saya ke arah yang benar.

Jawaban

Bergi Oct 14 2020 at 21:20

Anda akan membutuhkan jsonb_array_elements_textekstraksi nilai ekstra jika Anda berurusan dengan array. Selesai dengan gabungan lateral:

SELECT XMLAGG(
  XMLELEMENT(
    NAME "CompanyTag", 
    XMLATTRIBUTES(
      attr.key AS "tagName", 
      values.element AS "tagValue"
    )
  )
) FROM jsonb_each(attributes) AS attr,
LATERAL jsonb_array_elements_text(CASE jsonb_typeof(attr.value)
  WHEN 'array' THEN attr.value
  ELSE jsonb_build_array(attr.value)
END) AS values(element)

( demo online , dengan permintaan lengkap)