XmlElement 子查询中的 Oracle 序列问题

Oracle squence problem in XmlElement subquery

有这个功能:

CREATE OR REPLACE FUNCTION get_seq_xi_pl9_wws2lvs
    RETURN NUMBER 
IS
BEGIN
    RETURN seq_xi_pl9_wws2lvs.NEXTVAL;
END get_seq_xi_pl9_wws2lvs;

并使用此示例查询:

SELECT id,
          ''
       || XMLELEMENT ("Request",
                      XMLELEMENT ("TransaktionsNr",
                                  id),
                      XMLELEMENT ("Zeitstempel",
                                  0),
                      (SELECT xmldaten
                         FROM DUAL))    AS xml_final
  FROM (SELECT id,
               xmldaten
          FROM (SELECT get_seq_xi_pl9_wws2lvs                           AS id,
                       (XMLELEMENT ("Bestellung",
                                    XMLELEMENT ("BestellNr",
                                                tmp_bsp.BestellNr)))    AS xmlDaten
                  FROM (SELECT 4711     AS BestellNr
                          FROM DUAL
                        UNION ALL
                        SELECT 4712     AS BestellNr
                          FROM DUAL) tmp_bsp)); 

这是输出:

ID XML_FINAL
347816 <Request><TransaktionsNr>347817</TransaktionsNr><Zeitstempel>0</Zeitstempel><Bestellung><BestellNr>4711</BestellNr></Bestellung></Request>
347818 <Request><TransaktionsNr>347819</TransaktionsNr><Zeitstempel>0</Zeitstempel><Bestellung><BestellNr>4712</BestellNr></Bestellung></Request>

在一行中,字段“ID”和 XmlElement“TransaktionsNr”(也有“ID”作为值)具有不同的值 - 我希望它们相同。

我做错了什么?

SQL 引擎选择不具体化子查询,并将函数调用推送到外部查询,在那里它会为每一行调用多次。您需要强制在调用它的子查询中评估函数,而不是允许 SQL 引擎重写查询。

一种方法是使用 sub-query 分解子句和具体化提示:

WITH data (bestellnr) AS (
  SELECT 4711 AS BestellNr FROM DUAL
UNION ALL
  SELECT 4712 AS BestellNr FROM DUAL
),
ids (id, bestellnr) AS (
  SELECT /*+ materialize */ 
         get_seq_xi_pl9_wws2lvs,
         bestellnr
  FROM   data
)
SELECT id,
       XMLELEMENT (
           "Request",
           XMLELEMENT ("TransaktionsNr", id),
           XMLELEMENT ("Zeitstempel", 0),
           XMLELEMENT(
             "Bestellung",
             XMLELEMENT ("BestellNr", BestellNr)
           )
       ).getStringVal() AS xml_final
FROM   ids;

输出:

ID XML_FINAL
1 <Request><TransaktionsNr>1</TransaktionsNr><Zeitstempel>0</Zeitstempel><Bestellung><BestellNr>4711</BestellNr></Bestellung></Request>
2 <Request><TransaktionsNr>2</TransaktionsNr><Zeitstempel>0</Zeitstempel><Bestellung><BestellNr>4712</BestellNr></Bestellung></Request>

如果您不想使用提示,那么您可以添加(看似无用的)过滤器 WHERE ROWNUM >= 1,这也将强制 SQL 引擎在此时具体化查询。

SELECT id,
       XMLELEMENT (
           "Request",
           XMLELEMENT ("TransaktionsNr", id),
           XMLELEMENT ("Zeitstempel", 0),
           XMLELEMENT(
             "Bestellung",
             XMLELEMENT ("BestellNr", BestellNr)
           )
       ).getStringVal() AS xml_final
FROM   (
  SELECT get_seq_xi_pl9_wws2lvs AS id,
         bestellnr
  FROM   (
    SELECT 4711 AS BestellNr FROM DUAL UNION ALL
    SELECT 4712 AS BestellNr FROM DUAL
  )
  WHERE  ROWNUM >= 1
);

db<>fiddle here