none
SELECT EM XML RRS feed

  • Pergunta

  • Olá,

     

    Estou com o seguinte XML:

    <ExportacaoDeProdutos>

      <Item Produto="Produto 01">

        <Preco>50,00</Preco>

      </Item>

      <Item Produto="Produto 02">

        <Preco>60,00</Preco>

      </Item>

      <Item Produto="Produto 03">

        <Preco>30,00</Preco>

      </Item>

    </ExportacaoDeProdutos>

     

    E como estudo, queria trazer todos os produtos e seus reespectivos precos, tentei o select:

    SELECT

    @XML.value('(/ExportacaoDeProdutos/Item/@Produto)[1]','VARCHAR(50)') AS Produto,

    @XML.value('(/ExportacaoDeProdutos/Item/Preco)[1]','VARCHAR(50)') AS Preco

    Mas dessa forma só me traz o produto 1, conforme numero [1], alterando para 2 somente o 2, e assim vai, eu preciso listar todos de uma vez, como faço isso?


    Fabrizzio A. Caputo
    Certificações: Oracle OCA 11g, MCITP SQL Server 2008 Implementation and Maintenance
    Blog Pessoal: www.fabrizziocaputo.wordpress.com
    Blog Empresa: www.tripletech.com.br/blog
    Twitter: @FabrizzioCaputo
    Email: fabrizzio.antoniaci@gmail.com
    quarta-feira, 20 de julho de 2011 14:08
    Moderador

Respostas

  • Boa Tarde,

    O uso do método Query é uma alternativa, mas para retornar algo tabular (e não XML), é possível resolver com o Nodes ou com o OpenXML (meu voto vai para o nodes).

    DECLARE @xml XML
    SET @xml = '<ExportacaoDeProdutos>
       <Item Produto="Produto 01">
         <Preco>50.00</Preco>
       </Item>
       <Item Produto="Produto 02">
         <Preco>60.00</Preco>
       </Item>
       <Item Produto="Produto 03">
         <Preco>30.00</Preco>
       </Item>
     </ExportacaoDeProdutos>'

    -- Uso do Nodes 
    SELECT
     E.I.value('(../@Produto)[1]','NVARCHAR(20)') As Produto,
     E.I.value('(.)','SMALLMONEY') As Preco
    FROM @XML.nodes('/ExportacaoDeProdutos/Item/Preco') E(I)

    -- Uso do OPENXML
    DECLARE @IHandle INT

    -- Cria um Handle para apontar para o documento em memória
    EXEC sp_xml_preparedocument @IHandle OUTPUT, @xml
    SELECT *
    FROM OPENXML(@IHandle, N'/ExportacaoDeProdutos/Item/Preco')
    WITH (Produto NVARCHAR(20) '(../@Produto)[1]', Preco SMALLMONEY '(.)')

    -- Remove o ponteiro
    EXEC sp_xml_removedocument @IHandle

    [ ]s,

    Gustavo Maia Aguiar
    http://gustavomaiaaguiar.wordpress.com


    Classifique as respostas. O seu feedback é imprescindível
    quarta-feira, 20 de julho de 2011 19:56
  • Oi Fabrizzio,

    Quando comecei a estudar XML deu alguns "nós", mas depois de uma monografia de pós nesse assunto, eu até que gostei...

    Quando você navega no XML, é preciso sempre ir ao nó mais fundo para depois ir aos nós superiores. Suponha a seguinte estrutura:

    <Cliente Nome="João">
    <Carro>Fiat Brava</Carro>
    <Carro>Fiat Stilo</Carro>
    </Cliente>

    Poderíamos navegar até Carro (/Cliente/Carro) para capturar os valores dos nós "Carro". Entretanto, como Cliente é o Pai, é preciso navegar um nó acima (por isso o ..) com a expressão XPath (../Cliente/@Nome). O ".." é para dizer que iremos subir um nível acima do nível "Carro", ou seja, iremos para o nível "Cliente". Como desejamos recuperar o valor do atributo Nome, é preciso o @Nome para recuperá-lo.

    Pode parecer estranho termos de "descer" e depois "subir". Afinal não seria mais fácil simplesmente parar no ponto mais alto (Cliente) e descer até o nível Carro ao invés de ir até Carro e subir até cliente ? Com certeza seria mais fácil e a XQuery em sua essência prevê essa possibilidade. Entretanto, dado a natureza atômica que um modelo relacional exige não é possível fazê-lo. Se colocássemos a consulta como /Cliente e depois extraíssemos ./Carro teríamos um problema. Teríamos dois carros para representar um único valor e não seria atômico ("XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'". Se um pai pode ter vários filhos, não é possível apenas na navegação garantir a atomicidade. Como um filho nunca terá vários pais, sabemos que se formos até o nível mais baixo, só haverá um "pai" acima garantindo a atomicidade. Por isso temos de fazer dessa maneira (e muitas vezes colocar [1] nas expressões).

    Eis uma explicação que tenho muita dificuldade de fazer nas minhas aulas como MCT.

    [ ]s,

    Gustavo Maia Aguiar
    http://gustavomaiaaguiar.wordpress.com


    Classifique as respostas. O seu feedback é imprescindível
    quarta-feira, 20 de julho de 2011 23:18

Todas as Respostas

  • Olá Fabrizzio Caputo, 

    Eu fiz a seguinte programação, não sei se é o que vc precisa.

     

    DECLARE @XML XML

    SET @XML = '

    <ExportacaoDeProdutos>

      <Item Produto="Produto 01">

        <Preco>50,00</Preco>

      </Item>

      <Item Produto="Produto 02">

        <Preco>60,00</Preco>

      </Item>

      <Item Produto="Produto 03">

        <Preco>30,00</Preco>

      </Item>

    </ExportacaoDeProdutos>'

    DECLARE @SELECIONAR_PRODUTOS XML, @XML_PRODUTOS XML

    SET @SELECIONAR_PRODUTOS =  (SELECT  @XML.query('for $getProdutos in /ExportacaoDeProdutos/Item/@Produto return <Produtos>{string($getProdutos)}</Produtos>')) ;

    SELECT @SELECIONAR_PRODUTOS

    Espero ter ajudado você.

     

     

    • Sugerido como Resposta Diogo Luiz quarta-feira, 20 de julho de 2011 20:10
    quarta-feira, 20 de julho de 2011 17:57
  • Boa Tarde,

    O uso do método Query é uma alternativa, mas para retornar algo tabular (e não XML), é possível resolver com o Nodes ou com o OpenXML (meu voto vai para o nodes).

    DECLARE @xml XML
    SET @xml = '<ExportacaoDeProdutos>
       <Item Produto="Produto 01">
         <Preco>50.00</Preco>
       </Item>
       <Item Produto="Produto 02">
         <Preco>60.00</Preco>
       </Item>
       <Item Produto="Produto 03">
         <Preco>30.00</Preco>
       </Item>
     </ExportacaoDeProdutos>'

    -- Uso do Nodes 
    SELECT
     E.I.value('(../@Produto)[1]','NVARCHAR(20)') As Produto,
     E.I.value('(.)','SMALLMONEY') As Preco
    FROM @XML.nodes('/ExportacaoDeProdutos/Item/Preco') E(I)

    -- Uso do OPENXML
    DECLARE @IHandle INT

    -- Cria um Handle para apontar para o documento em memória
    EXEC sp_xml_preparedocument @IHandle OUTPUT, @xml
    SELECT *
    FROM OPENXML(@IHandle, N'/ExportacaoDeProdutos/Item/Preco')
    WITH (Produto NVARCHAR(20) '(../@Produto)[1]', Preco SMALLMONEY '(.)')

    -- Remove o ponteiro
    EXEC sp_xml_removedocument @IHandle

    [ ]s,

    Gustavo Maia Aguiar
    http://gustavomaiaaguiar.wordpress.com


    Classifique as respostas. O seu feedback é imprescindível
    quarta-feira, 20 de julho de 2011 19:56
  • Gustavo,

     

    Show de bola, é isso mesmo, fui para a prova 433 sem saber XML, passei, mas sei que errei todas de select em xml rs...

     

    Todo caso, só uma duvia, então no FROM eu coloco todos os niveis inclusive o preco certo.

    E o (.) quer dizer que ja é no node, no caso, preco, porem, por que para pegar o produto, eu coloco ..?


    Fabrizzio A. Caputo
    Certificações: Oracle OCA 11g, MCITP SQL Server 2008 Implementation and Maintenance
    Blog Pessoal: www.fabrizziocaputo.wordpress.com
    Blog Empresa: www.tripletech.com.br/blog
    Twitter: @FabrizzioCaputo
    Email: fabrizzio.antoniaci@gmail.com
    quarta-feira, 20 de julho de 2011 21:02
    Moderador
  • Oi Fabrizzio,

    Quando comecei a estudar XML deu alguns "nós", mas depois de uma monografia de pós nesse assunto, eu até que gostei...

    Quando você navega no XML, é preciso sempre ir ao nó mais fundo para depois ir aos nós superiores. Suponha a seguinte estrutura:

    <Cliente Nome="João">
    <Carro>Fiat Brava</Carro>
    <Carro>Fiat Stilo</Carro>
    </Cliente>

    Poderíamos navegar até Carro (/Cliente/Carro) para capturar os valores dos nós "Carro". Entretanto, como Cliente é o Pai, é preciso navegar um nó acima (por isso o ..) com a expressão XPath (../Cliente/@Nome). O ".." é para dizer que iremos subir um nível acima do nível "Carro", ou seja, iremos para o nível "Cliente". Como desejamos recuperar o valor do atributo Nome, é preciso o @Nome para recuperá-lo.

    Pode parecer estranho termos de "descer" e depois "subir". Afinal não seria mais fácil simplesmente parar no ponto mais alto (Cliente) e descer até o nível Carro ao invés de ir até Carro e subir até cliente ? Com certeza seria mais fácil e a XQuery em sua essência prevê essa possibilidade. Entretanto, dado a natureza atômica que um modelo relacional exige não é possível fazê-lo. Se colocássemos a consulta como /Cliente e depois extraíssemos ./Carro teríamos um problema. Teríamos dois carros para representar um único valor e não seria atômico ("XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'". Se um pai pode ter vários filhos, não é possível apenas na navegação garantir a atomicidade. Como um filho nunca terá vários pais, sabemos que se formos até o nível mais baixo, só haverá um "pai" acima garantindo a atomicidade. Por isso temos de fazer dessa maneira (e muitas vezes colocar [1] nas expressões).

    Eis uma explicação que tenho muita dificuldade de fazer nas minhas aulas como MCT.

    [ ]s,

    Gustavo Maia Aguiar
    http://gustavomaiaaguiar.wordpress.com


    Classifique as respostas. O seu feedback é imprescindível
    quarta-feira, 20 de julho de 2011 23:18
  • Gustavo!

    Perfeito!


    Fabrizzio A. Caputo
    Certificações: Oracle OCA 11g, MCITP SQL Server 2008 Implementation and Maintenance
    Blog Pessoal: www.fabrizziocaputo.wordpress.com
    Blog Empresa: www.tripletech.com.br/blog
    Twitter: @FabrizzioCaputo
    Email: fabrizzio.antoniaci@gmail.com
    quinta-feira, 21 de julho de 2011 01:14
    Moderador