convert FOR XML as text

  • hi,

    I would like to convert the result of a SELECT FOR XML query into a text field to be able to manipulate the result in my development language.

    if there is only one level for my xml. No problem. I use convert or cast as text and it's ok.

    But if i have more than one level and i need to use an union. i have got an error message  :

    Msg 1086, Niveau 15

    La clause FOR XML n'est pas valide dans les vues, les fonctions inline, les tables dérivées et les sous-requêtes lorsque celles-ci contiennent un opérateur défini. Pour contourner ce problème, encapsulez la clause SELECT contenant un opérateur défini au moyen d'une syntaxe de table dérivée et appliquez FOR XML à celle-ci.

    The FOR XML clause is not valid in views, inline functions, derived tables and subqueries when these contain a defined operator. To work around this problem, wrap the SELECT clause containing an operator defined using derived table syntax and apply FOR XML to it.

    i have made a short example to have this result :

    <STOCK_OUT>
    <Header>
    <DateStock>02/01/2020</DateStock>
    <FormatDate>103</FormatDate>
    <HeureStock>12:45</HeureStock>
    <FormatHeure>205</FormatHeure>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    </Header>
    </STOCK_OUT>

    the SQL

    select cast((
    select distinct
    1 as Tag,
    0 as Parent,
    convert(varchar(10), getdate(), 103) as [Header!1!DateStock!ELEMENT],
    '103' as [Header!1!FormatDate!ELEMENT],
    left(convert(varchar(10), getdate(), 108), 5) as [Header!1!HeureStock!ELEMENT],
    '205' as [Header!1!FormatHeure!ELEMENT],
    NULL as [Line!2!Item!ELEMENT],
    NULL as [Line!2!QTY!ELEMENT]
    UNION ALL
    select top 5
    2 as Tag,
    1 as Parent,
    NULL,
    NULL,
    NULL,
    NULL,
    ART_CODE as 'Item',
    cast(STK_qte as int) as Qty
    from STK_DAT

    FOR XML EXPLICIT ,ROOT('STOCK_OUT')
    ) as TEXT)

    thanks

  • frederic.leurs wrote:

    hi,

    I would like to convert the result of a SELECT FOR XML query into a text field to be able to manipulate the result in my development language.

    if there is only one level for my xml. No problem. I use convert or cast as text and it's ok.

    But if i have more than one level and i need to use an union. i have got an error message  :

    Msg 1086, Niveau 15

    La clause FOR XML n'est pas valide dans les vues, les fonctions inline, les tables dérivées et les sous-requêtes lorsque celles-ci contiennent un opérateur défini. Pour contourner ce problème, encapsulez la clause SELECT contenant un opérateur défini au moyen d'une syntaxe de table dérivée et appliquez FOR XML à celle-ci.

    The FOR XML clause is not valid in views, inline functions, derived tables and subqueries when these contain a defined operator. To work around this problem, wrap the SELECT clause containing an operator defined using derived table syntax and apply FOR XML to it.

    i have made a short example to have this result :

    <STOCK_OUT>
    <Header>
    <DateStock>02/01/2020</DateStock>
    <FormatDate>103</FormatDate>
    <HeureStock>12:45</HeureStock>
    <FormatHeure>205</FormatHeure>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    <Line>
    <Item>SP-10268363</Item>
    <QTY>1</QTY>
    </Line>
    </Header>
    </STOCK_OUT>

    the SQL

    select cast((
    select distinct
    1 as Tag,
    0 as Parent,
    convert(varchar(10), getdate(), 103) as [Header!1!DateStock!ELEMENT],
    '103' as [Header!1!FormatDate!ELEMENT],
    left(convert(varchar(10), getdate(), 108), 5) as [Header!1!HeureStock!ELEMENT],
    '205' as [Header!1!FormatHeure!ELEMENT],
    NULL as [Line!2!Item!ELEMENT],
    NULL as [Line!2!QTY!ELEMENT]
    UNION ALL
    select top 5
    2 as Tag,
    1 as Parent,
    NULL,
    NULL,
    NULL,
    NULL,
    ART_CODE as 'Item',
    cast(STK_qte as int) as Qty
    from STK_DAT

    FOR XML EXPLICIT ,ROOT('STOCK_OUT')
    ) as TEXT)

    thanks

    Can you please post the DDL (create table) script and sample data as insert statement?

    😎

    This looks like an elementary problem to me.

  • Same thinks without a table

    select cast((
    select distinct
    1 as Tag,
    0 as Parent,
    convert(varchar(10), getdate(), 103) as [Header!1!DateStock!ELEMENT],
    '103' as [Header!1!FormatDate!ELEMENT],
    left(convert(varchar(10), getdate(), 108), 5) as [Header!1!HeureStock!ELEMENT],
    '205' as [Header!1!FormatHeure!ELEMENT],
    NULL as [Line!2!Item!ELEMENT],
    NULL as [Line!2!QTY!ELEMENT]
    UNION ALL
    select Tag,Parent, DateStock,FormatDate,HeureStock,FormatHeure,Item,QTY
    from (values(2 , 1 , NULL,NULL, NULL,NULL,'ITEM1',10),(2, 1, NULL,NULL, NULL,NULL,'ITEM2',20)) a ( Tag,Parent, DateStock,FormatDate,HeureStock,FormatHeure,Item,QTY )

    FOR XML EXPLICIT ,ROOT('STOCK_OUT')
    ) as TEXT)

    result :

    <STOCK_OUT>
    <Header>
    <DateStock>02/01/2020</DateStock>
    <FormatDate>103</FormatDate>
    <HeureStock>14:34</HeureStock>
    <FormatHeure>205</FormatHeure>
    <Line>
    <Item>ITEM1</Item>
    <QTY>10</QTY>
    </Line>
    <Line>
    <Item>ITEM2</Item>
    <QTY>20</QTY>
    </Line>
    </Header>
    </STOCK_OUT>

     

  • The problem is the order of precedence of operators.  The FOR XML is evaluated before the UNION, but your query requires that it be evaluated after.  Use a CTE for the UNION to ensure the proper ordering.

    WITH edge_table AS
    (
    select distinct
    1 as Tag,
    0 as Parent,
    convert(varchar(10), getdate(), 103) as [Header!1!DateStock!ELEMENT],
    '103' as [Header!1!FormatDate!ELEMENT],
    left(convert(varchar(10), getdate(), 108), 5) as [Header!1!HeureStock!ELEMENT],
    '205' as [Header!1!FormatHeure!ELEMENT],
    NULL as [Line!2!Item!ELEMENT],
    NULL as [Line!2!QTY!ELEMENT]
    UNION ALL
    select top 5
    2 as Tag,
    1 as Parent,
    NULL,
    NULL,
    NULL,
    NULL,
    ART_CODE as 'Item',
    cast(STK_qte as int) as Qty
    from STK_DAT
    )

    select cast((
    SELECT *
    FROM edge_table
    FOR XML EXPLICIT ,ROOT('STOCK_OUT')
    ) as TEXT)

     

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • thanks a lot. It was so simple. You are right : it was a basic problem.

    Is there an another way to get the result of a for XML ( without cast ?) ?  i use the MSOLEDBSQL  driver.

     

  • Few thoughts:

    1. Strongly recommend that you don't use the TEXT data type, better options are either VARCHAR(MAX) or NVARCHAR(MAX)

    2. Using FOR XML PATH() is simpler and more legible than FOR XML EXPLICIT

    😎

    Here is an example using FOR XML PATH

    USE TEEST;
    GO
    SET NOCOUNT ON;
    ;WITH BASE_DATA AS
    (
    SELECT
    1 as Parent
    ,CONVERT(VARCHAR(10), getdate(), 103) AS [DateStock]
    ,'103' as [FormatDate]
    ,LEFT(CONVERT(VARCHAR(10), getdate(), 108), 5) AS [HeureStock]
    ,'205' AS [FormatHeure]
    )
    ,ITEM_DATA(Parent, Item,QTY) AS
    (
    SELECT 1,'ITEM1',10 UNION ALL
    SELECT 1,'ITEM2',20
    )
    SELECT CONVERT(VARCHAR(MAX),(
    SELECT
    BD.DateStock
    ,BD.FormatDate
    ,BD.HeureStock
    ,BD.FormatHeure
    ,(
    SELECT
    IT.Item AS 'Item'
    ,IT.QTY AS 'QTY'
    FROM ITEM_DATA IT
    WHERE IT.Parent = BD.Parent
    FOR XML PATH('Line'),TYPE
    )
    FROM BASE_DATA BD
    FOR XML PATH('Header'), ROOT('STOCK_OUT')
    ),0) AS OUT_TEXT;
  • Thanks for you contribution. I know  path, explicit or Auto. I have just made a simple example in a couple of minutes. In the real life, it's always a little bit more complicate...

    My question was not clear enough :

    When you use the MSOLEDBSQL  driver, Is there a way to retrieve the result of a FOR XML without using a CAST or Convert. What type of field should retrieve the result of a query with FOR XML.

    I have tried several case in my language, but none of them work. The only one I found that works is the one with a cast.

    When you launch it in MSSMS, you see that the result is not like a standard sql.

Viewing 7 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic. Login to reply