Usuário com melhor resposta
SELECT EM XML

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
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- Sugerido como Resposta Gustavo Maia Aguiar quarta-feira, 20 de julho de 2011 20:06
- Marcado como Resposta Fabrizzio CaputoModerator quarta-feira, 20 de julho de 2011 21:02
-
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- Sugerido como Resposta Gustavo Maia Aguiar quarta-feira, 20 de julho de 2011 23:18
- Marcado como Resposta Fabrizzio CaputoModerator quinta-feira, 21 de julho de 2011 01:14
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
-
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- Sugerido como Resposta Gustavo Maia Aguiar quarta-feira, 20 de julho de 2011 20:06
- Marcado como Resposta Fabrizzio CaputoModerator quarta-feira, 20 de julho de 2011 21:02
-
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 -
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- Sugerido como Resposta Gustavo Maia Aguiar quarta-feira, 20 de julho de 2011 23:18
- Marcado como Resposta Fabrizzio CaputoModerator quinta-feira, 21 de julho de 2011 01:14
-
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