Em Novembro vamos aproveitar a vinda do Fabiano para ministrar um treinamento pela Nimbus e abusar um pouco dele, fazendo com que ele fale por mais de 10 horas sobre o SQL Server em um só dia.
Para poupar tempo e dado que estamos longe do país neste momento, ele me mandou rapidinho a descrição da apresentação em inglês, mas fique tranquilo que essa sessão será apresentada em português.
De resto vocês já sabem o que fazer, por favor confirmar presença com nome e e-mail no Google Groups. Para aqueles que não estão no grupo, basta ir até http://groups.google.com/group/sqlserverdf, fazer sua inscrição e aguardar minha moderação.
Data e horário: 12/11/2015, das 18:30h às 20:30h
Local: Xperts Trainning Center
Palestrante: Fabiano Neves Amorim
Título: Writing t-sql like a boss
Descrição: SQL is a tricky programming language, if you work with SQL Server in any capacity, as a developer, DBA, or a SQL user, you need to know how to write a good T-SQL code. A poorly written query will bring even the best hardware to its knees, for a truly performing system, there is no substitute for properly written queries that takes advantage of all SQL Server has to offer. Come to this session to learn how re-write a query and see many tips on what to do to make queries execute as fast as possible.
Mini-cv do palestrante: Trabalha a mais de 10 anos exclusivamente com SQL Server, MVP em plataforma de dados desde 2011, especialista em banco de dados e aficionado por performance tuning. Palestrante em eventos nacionais e internacionais. Atualmente trabalha como consultor na Pythian e instrutor na Sr.Nimbus. Quando não está trabalhando gosta de demonstrar seus talentos nos gramados de futebol (leia-se craque ;p), ler, ir ao cinema com a esposa e curtir o filho, não necessariamente nessa ordem e vice-versa.
Xperts Trainning Center
SHIS QI 15 Conjunto 8/9 Área especial Bloco D, Subsolo - Lago Sul (ao final da rua)
CEP 71635-565 - Brasília - DF
Telefone: (61) 4063-8177 | 9545-9241
Ponto de referência: Próximo ao Hospital Brasília; Acesso é mais fácil se feito ao lado da escola Red Balloon;
Abraços
Luciano Caixeta Moreira - {Luti}
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
www.srnimbus.com.br
SELECT CAST (power(CrazyIdeas, Curiosity) * (RealLifeExperience + MyMistakes)) / FreeTime) AS VARCHAR(MAX)) FROM MyBrain WITH (NOLOCK, INDEX('idx_Neuron')) WHERE ThingsIThinkIKnow in ('SQL Server', 'DB2', '.NET', 'Cloud')
Mostrando postagens com marcador T-SQL. Mostrar todas as postagens
Mostrando postagens com marcador T-SQL. Mostrar todas as postagens
segunda-feira, 2 de novembro de 2015
terça-feira, 9 de outubro de 2012
Bug na compilação do T-SQL
Hoje eu estava codificando uma função e encontrei um bug na compilação do SQL Server! Vamos ver se você encontra? No meu caso eram centenas de linhas de código, então para simplificar sua vida eu escrevi uma função e enchi um pouco de linguiça...
USE tempdb
GO
IF (OBJECT_ID('dbo.fn_Teste', 'FN') IS NOT NULL)
DROP FUNCTION dbo.fn_Teste
go
CREATE FUNCTION dbo.fn_Teste(@P1 INT, @P2 INT)
RETURNS INT
AS
BEGIN
DECLARE @Retorno INT
IF (@P1 = 1)
BEGIN
SELECT @Retorno = COUNT(*)
FROM sys.objects
WHERE object_id > @P2
END
IF (@P1 = 2)
BEGIN
SELECT @Retorno = COUNT(*)
FROM sys.indexes AS S
WHERE S.index_id < @P2
END
IF (@P1 = 3)
BEGIN
SELECT @Retorno = COUNT(*)
FROM sys.columns
WHERE system_type_id = dbo.fn_Teste(1)
END
IF (@P1 = 4)
BEGIN
SELECT @Retorno = COUNT(*)
FROM sys.allocation_units AS S
WHERE S.total_pages > @P2
END
RETURN @Retorno
END
go
SELECT dbo.fn_Teste(1, 4)
Na hora que você executar o SELECT a consulta vai receber a seguinte mensagem de erro: “Msg 313, Level 16, State 2, Line 1 - An insufficient number of arguments were supplied for the procedure or function dbo.fn_Teste.“.
Oxi, número de parâmetros errados? Ou estou muito doidão ou estou certo e coloquei os 2 parâmetros na chamada da função, e pau! Já viu o problema? Se sim, ótimo, caso contrário continuemos... Na dúvida eu fui fazer outro teste, apago a função original, coloco um 2 no nome e executo o script abaixo.
IF (OBJECT_ID('dbo.fn_Teste', 'FN') IS NOT NULL)
DROP FUNCTION dbo.fn_Teste
go
IF (OBJECT_ID('dbo.fn_Teste2', 'FN') IS NOT NULL)
DROP FUNCTION dbo.fn_Teste2
go
CREATE FUNCTION dbo.fn_Teste2(@P1 INT, @P2 INT)
RETURNS INT
AS
BEGIN
DECLARE @Retorno INT
IF (@P1 = 1)
BEGIN
SELECT @Retorno = COUNT(*)
FROM sys.objects
WHERE object_id > @P2
END
IF (@P1 = 2)
BEGIN
SELECT @Retorno = COUNT(*)
FROM sys.indexes AS S
WHERE S.index_id < @P2
END
IF (@P1 = 3)
BEGIN
SELECT @Retorno = COUNT(*)
FROM sys.columns
WHERE system_type_id = dbo.fn_Teste(1)
END
IF (@P1 = 4)
BEGIN
SELECT @Retorno = COUNT(*)
FROM sys.allocation_units AS S
WHERE S.total_pages > @P2
END
RETURN @Retorno
END
go
SELECT dbo.fn_Teste2(1, 4)
Resultado: funcionou! Ihhh, lascou tudo. Por que a fn_Teste2 funcionou e a primeira não? Já sabe? Então te dou um tempinho para pensar antes de continuar lendo...
(Olha o tempo galera! Agora no placar Leitor 1 x 0 SQL Server...)
Vamos lá...
Isso não é BUG do SQL Server coisa nenhuma, só foi uma brincadeira da minha parte. O que estávamos vendo aqui é a resolução deferida do SQL Server em ação.
Quando criamos a função fn_Teste se você reparar no código da função eu estou chamando a função fn_Teste novamente (no IF = 3), só que com a parametrização errada (1 parâmetro somente). Na criação da fn_Teste esse objeto efetivamente ainda não foi criado, então o corpo da função referencia outra função que ainda não existe (ela mesma!), portanto a validação é deferida.
No momento que executamos a chamada a fn_Teste, o problema com os parâmetros não está na sua chamada (são 2 parâmetros, ok!), mas sim na chamada da função no meio do T-SQL, pois já que o objeto existe o SQL Server faz o binding e verifica o problema.
O curioso fica por conta da fn_Teste2, no script de propósito eu apaguei a fn_Teste para temos uma validação deferida. E na hora que a função foi executada a fn_Teste também não existia, então não tendo como validar a fn_Teste, a função executou com sucesso. Se você tentar executar a consulta “SELECT dbo.fn_Teste2(3, 4)”, aí vai receber um erro, pois sua chamada vai entrar no IF que precisa da função inexistente.
Curioso é o seguinte, quando você invocar fn_Teste2(1, 4) e depois consultar o plan cache vai ver a entrada da função, usecount sendo incrementado, porém o plano não está em cache! Nesse momento se você criar fn_Teste(), mesmo com o corpo do fn_Teste2 estando com a chamada errada para fn_Teste (somente um parâmetro), a chamada para fn_Teste2(1, 4) ainda vai funcionar!
Para ver o erro você vai precisar chamar DBCC FREEPROCCACHE e depois fn_Teste2(1, 4), aí nessa compilação como o fn_Teste existe, a operação não será deferida e o número incorreto de parâmetros será detectado.
Brincadeiras com o T-SQL, eu me diverti...
Abraços
sr. Nimbus Serviços em Tecnologia - www.srnimbus.com.br
quinta-feira, 20 de janeiro de 2011
[SQLServerDF] Encontro IX - Testes de unidade com T-SQL
Bom dia pessoal, tudo bem?
Vamos começar as atividades de 2011 com mais um encontro do grupo SQLServerDF? Anotei as dicas de vocês e estou em contato com alguns palestrantes para organizar nossa agenda, mas como eu ainda estou negociando datas e não quero adiar mais nosso início, vou aproveitar e falar sobre um tema que gosto e tenho utilizado bastante.
As informações sobre o encontro são:
Local: Auditório da Microsoft - Edifício Corporate Financial Center, sala 302
Data e horário: 26/01/2011, 17:00h ~ 19:30h
Tema: Testes de unidade com T-SQL
Descrição: Um desenvolvedor profissional utilizando C# ou Java está acostumado a criar testes de unidade (xUnit tests) para desenvolver um código mais robusto, resistente e verificável quando temos alterações de regras de negócio ou refactorings. Porque o programador T-SQL não pode usar os mesmos princípios com T-SQL?
Nessa sessão eu vou demonstrar como escrever testes de unidades eficientes para os procedimentos e funções, testando o curso básico correto, cursos alternativos, exceções esperadas e se o dado está sendo corretamente manipulado por seu código. Nesse primeiro encontro provavelmente não teremos tempo para utilizar o Visual Studio 2010 ou outra ferramenta de terceiros, somente código T-SQL e batches para nos ajudar a automatizar os testes (o que lá fora eles chamariam de poor man´s T-SQL testing :-)).
Palestrante: Luciano [Luti] Moreira
Favor mandar para o grupo um e-mail confirmando sua presença, pois o tamanho do auditório não é ilimitado.
[]s
Luciano Caixeta Moreira - {Luti}
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
www.srnimbus.com.br
Vamos começar as atividades de 2011 com mais um encontro do grupo SQLServerDF? Anotei as dicas de vocês e estou em contato com alguns palestrantes para organizar nossa agenda, mas como eu ainda estou negociando datas e não quero adiar mais nosso início, vou aproveitar e falar sobre um tema que gosto e tenho utilizado bastante.
As informações sobre o encontro são:
Local: Auditório da Microsoft - Edifício Corporate Financial Center, sala 302
Data e horário: 26/01/2011, 17:00h ~ 19:30h
Tema: Testes de unidade com T-SQL
Descrição: Um desenvolvedor profissional utilizando C# ou Java está acostumado a criar testes de unidade (xUnit tests) para desenvolver um código mais robusto, resistente e verificável quando temos alterações de regras de negócio ou refactorings. Porque o programador T-SQL não pode usar os mesmos princípios com T-SQL?
Nessa sessão eu vou demonstrar como escrever testes de unidades eficientes para os procedimentos e funções, testando o curso básico correto, cursos alternativos, exceções esperadas e se o dado está sendo corretamente manipulado por seu código. Nesse primeiro encontro provavelmente não teremos tempo para utilizar o Visual Studio 2010 ou outra ferramenta de terceiros, somente código T-SQL e batches para nos ajudar a automatizar os testes (o que lá fora eles chamariam de poor man´s T-SQL testing :-)).
Palestrante: Luciano [Luti] Moreira
Favor mandar para o grupo um e-mail confirmando sua presença, pois o tamanho do auditório não é ilimitado.
[]s
Luciano Caixeta Moreira - {Luti}
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
www.srnimbus.com.br
Marcadores:
SQLServerDF,
T-SQL,
testes de unidade
terça-feira, 24 de novembro de 2009
Gerando script das views para suas tabelas
Bom dia pessoal.
Hoje eu estava trabalhando em um cliente e precisei fazer uma coisa bem manual: Criar uma série de views com um nome diferente da tabela que estamos consultando, mas contendo todos os campos da tabela original.
Qual o motivo disso? Nós estamos criando um ambiente temporário onde estou jogando um monte de informações e vamos expor uma "interface" usando visões, que o usuário de negócio vai poder consultar à vontade e eventualmente criar consultas e relatórios. Então usaremos essa abstração, que nesse momento refletirá boa parte das tabelas, para evitar um pouco de retrabalho e atrito entre os lados, caso a estrutura mude, e dividir bem a questão de segurança.
Agora que vocês estão contextualizados vamos ver o que bolei... Eu poderia simplesmente sair escrevendo umas 50 visões com todos os campos, mas isso iria levar um tempão, então montei um script rápido que me ajudaria a gerar o código que preciso.
Seu mecanismo básico é o seguinte: tenho uma tabela temporária com N registros contendo o nome do esquema, da tabela existente e o nome que quero dar para a view. Bom base nessa tabela eu utilizo o CROSS APPLY para gerar uma string usando informações da sys.objects, sys.columns e sys.schemas, usando o truque com XML que já coloquei aqui no blog (http://luticm.blogspot.com/2009/06/gerar-registros-em-forma-de-colunas.html).
Segue o código T-SQL utilizando o AdventureWorks2008 para vocês brincarem e, quem sabe, utilizarem em algum momento, customizando o que será gerado.
USE AdventureWorks2008
go
WITH TabelaView AS
(SELECT Esquema, Tabela, Visao
FROM ( VALUES
('Sales', 'SalesOrderHeader', 'Venda'),
('Sales', 'SalesOrderDetail', 'DetalheVenda'),
('Production', 'Product', 'Produto'))
AS T(Esquema, Tabela, Visao))
SELECT
CodigoViews.Instrucao
FROM TabelaView
CROSS APPLY
(SELECT
'
IF OBJECT_ID(''vw_'+ TabelaView.Visao +''') IS NOT NULL
DROP VIEW dbo.[vw_'+ TabelaView.Visao +']
go
CREATE VIEW dbo.vw_' + TabelaView.Visao + '
WITH SCHEMABINDING
AS
SELECT ' +
STUFF(
(SELECT N', ' + QUOTENAME(SC.name) AS [text()]
FROM SYS.columns AS SC
INNER JOIN sys.objects AS SO
ON SO.object_id = SC.object_id
INNER JOIN sys.schemas AS SS
ON SO.schema_id = SS.schema_id
WHERE SO.type = 'U'
AND SO.name = TabelaView.Tabela
AND SS.name = TabelaView.Esquema
FOR XML PATH('')), 1, 2, N'') + '
FROM ' + TabelaView.Esquema + '.' + TabelaView.Tabela + '
go'
AS Instrucao) AS CodigoViews
go
E o código gerado é esse aqui:
IF OBJECT_ID('vw_Venda') IS NOT NULL
DROP VIEW dbo.[vw_Venda]
go
CREATE VIEW dbo.vw_Venda
WITH SCHEMABINDING
AS
SELECT [SalesOrderID], [RevisionNumber], [OrderDate], [DueDate], [ShipDate], [Status], [OnlineOrderFlag], [SalesOrderNumber], [PurchaseOrderNumber], [AccountNumber], [CustomerID], [SalesPersonID], [TerritoryID], [BillToAddressID], [ShipToAddressID], [ShipMethodID], [CreditCardID], [CreditCardApprovalCode], [CurrencyRateID], [SubTotal], [TaxAmt], [Freight], [TotalDue], [Comment], [rowguid], [ModifiedDate]
FROM Sales.SalesOrderHeader
go
IF OBJECT_ID('vw_DetalheVenda') IS NOT NULL
DROP VIEW dbo.[vw_DetalheVenda]
go
CREATE VIEW dbo.vw_DetalheVenda
WITH SCHEMABINDING
AS
SELECT [SalesOrderID], [SalesOrderDetailID], [CarrierTrackingNumber], [OrderQty], [ProductID], [SpecialOfferID], [UnitPrice], [UnitPriceDiscount], [LineTotal], [rowguid], [ModifiedDate]
FROM Sales.SalesOrderDetail
go
IF OBJECT_ID('vw_Produto') IS NOT NULL
DROP VIEW dbo.[vw_Produto]
go
CREATE VIEW dbo.vw_Produto
WITH SCHEMABINDING
AS
SELECT [ProductID], [Name], [ProductNumber], [MakeFlag], [FinishedGoodsFlag], [Color], [SafetyStockLevel], [ReorderPoint], [StandardCost], [ListPrice], [Size], [SizeUnitMeasureCode], [WeightUnitMeasureCode], [Weight], [DaysToManufacture], [ProductLine], [Class], [Style], [ProductSubcategoryID], [ProductModelID], [SellStartDate], [SellEndDate], [DiscontinuedDate], [rowguid], [ModifiedDate]
FROM Production.Product
go
Notem que o T-SQL é bem simples e fácil de ser alterado, então se eu quisesse omitir colunas do tipo uniqueidentifier ou remover campos com nome CodigoXXXXXXX, basta adicionar algumas cláusulas where no código.
Post rápido, mas espero que seja útil para alguém. Ou então pelo menos a idéia do T-SQL...
Você pode baixar o script aqui.
[]s
Luciano Caixeta Moreira - {Luti}
Chief Innovation Officer
Sr. Nimbus Serviços em Tecnologia Ltda
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
Hoje eu estava trabalhando em um cliente e precisei fazer uma coisa bem manual: Criar uma série de views com um nome diferente da tabela que estamos consultando, mas contendo todos os campos da tabela original.
Qual o motivo disso? Nós estamos criando um ambiente temporário onde estou jogando um monte de informações e vamos expor uma "interface" usando visões, que o usuário de negócio vai poder consultar à vontade e eventualmente criar consultas e relatórios. Então usaremos essa abstração, que nesse momento refletirá boa parte das tabelas, para evitar um pouco de retrabalho e atrito entre os lados, caso a estrutura mude, e dividir bem a questão de segurança.
Agora que vocês estão contextualizados vamos ver o que bolei... Eu poderia simplesmente sair escrevendo umas 50 visões com todos os campos, mas isso iria levar um tempão, então montei um script rápido que me ajudaria a gerar o código que preciso.
Seu mecanismo básico é o seguinte: tenho uma tabela temporária com N registros contendo o nome do esquema, da tabela existente e o nome que quero dar para a view. Bom base nessa tabela eu utilizo o CROSS APPLY para gerar uma string usando informações da sys.objects, sys.columns e sys.schemas, usando o truque com XML que já coloquei aqui no blog (http://luticm.blogspot.com/2009/06/gerar-registros-em-forma-de-colunas.html).
Segue o código T-SQL utilizando o AdventureWorks2008 para vocês brincarem e, quem sabe, utilizarem em algum momento, customizando o que será gerado.
USE AdventureWorks2008
go
WITH TabelaView AS
(SELECT Esquema, Tabela, Visao
FROM ( VALUES
('Sales', 'SalesOrderHeader', 'Venda'),
('Sales', 'SalesOrderDetail', 'DetalheVenda'),
('Production', 'Product', 'Produto'))
AS T(Esquema, Tabela, Visao))
SELECT
CodigoViews.Instrucao
FROM TabelaView
CROSS APPLY
(SELECT
'
IF OBJECT_ID(''vw_'+ TabelaView.Visao +''') IS NOT NULL
DROP VIEW dbo.[vw_'+ TabelaView.Visao +']
go
CREATE VIEW dbo.vw_' + TabelaView.Visao + '
WITH SCHEMABINDING
AS
SELECT ' +
STUFF(
(SELECT N', ' + QUOTENAME(SC.name) AS [text()]
FROM SYS.columns AS SC
INNER JOIN sys.objects AS SO
ON SO.object_id = SC.object_id
INNER JOIN sys.schemas AS SS
ON SO.schema_id = SS.schema_id
WHERE SO.type = 'U'
AND SO.name = TabelaView.Tabela
AND SS.name = TabelaView.Esquema
FOR XML PATH('')), 1, 2, N'') + '
FROM ' + TabelaView.Esquema + '.' + TabelaView.Tabela + '
go'
AS Instrucao) AS CodigoViews
go
E o código gerado é esse aqui:
IF OBJECT_ID('vw_Venda') IS NOT NULL
DROP VIEW dbo.[vw_Venda]
go
CREATE VIEW dbo.vw_Venda
WITH SCHEMABINDING
AS
SELECT [SalesOrderID], [RevisionNumber], [OrderDate], [DueDate], [ShipDate], [Status], [OnlineOrderFlag], [SalesOrderNumber], [PurchaseOrderNumber], [AccountNumber], [CustomerID], [SalesPersonID], [TerritoryID], [BillToAddressID], [ShipToAddressID], [ShipMethodID], [CreditCardID], [CreditCardApprovalCode], [CurrencyRateID], [SubTotal], [TaxAmt], [Freight], [TotalDue], [Comment], [rowguid], [ModifiedDate]
FROM Sales.SalesOrderHeader
go
IF OBJECT_ID('vw_DetalheVenda') IS NOT NULL
DROP VIEW dbo.[vw_DetalheVenda]
go
CREATE VIEW dbo.vw_DetalheVenda
WITH SCHEMABINDING
AS
SELECT [SalesOrderID], [SalesOrderDetailID], [CarrierTrackingNumber], [OrderQty], [ProductID], [SpecialOfferID], [UnitPrice], [UnitPriceDiscount], [LineTotal], [rowguid], [ModifiedDate]
FROM Sales.SalesOrderDetail
go
IF OBJECT_ID('vw_Produto') IS NOT NULL
DROP VIEW dbo.[vw_Produto]
go
CREATE VIEW dbo.vw_Produto
WITH SCHEMABINDING
AS
SELECT [ProductID], [Name], [ProductNumber], [MakeFlag], [FinishedGoodsFlag], [Color], [SafetyStockLevel], [ReorderPoint], [StandardCost], [ListPrice], [Size], [SizeUnitMeasureCode], [WeightUnitMeasureCode], [Weight], [DaysToManufacture], [ProductLine], [Class], [Style], [ProductSubcategoryID], [ProductModelID], [SellStartDate], [SellEndDate], [DiscontinuedDate], [rowguid], [ModifiedDate]
FROM Production.Product
go
Notem que o T-SQL é bem simples e fácil de ser alterado, então se eu quisesse omitir colunas do tipo uniqueidentifier ou remover campos com nome CodigoXXXXXXX, basta adicionar algumas cláusulas where no código.
Post rápido, mas espero que seja útil para alguém. Ou então pelo menos a idéia do T-SQL...
Você pode baixar o script aqui.
[]s
Luciano Caixeta Moreira - {Luti}
Chief Innovation Officer
Sr. Nimbus Serviços em Tecnologia Ltda
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
quinta-feira, 25 de junho de 2009
Gerar registros em forma de colunas? Peça ajuda ao XML!
Bom dia pessoal.
Já vi muita pergunta em fóruns onde o pessoal vive tentando arranjar um jeito de mostrar uma série de registros em uma só coluna, separado por vírgula ou sei lá. Aproveitei uma thread que estava rolando no MSDN para usar de base para esse pequeno artigo...
O problema era pegar a consulta abaixo e retornar o resultado em somente uma linha:
USE MSDB
go
SELECT TOP 2 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'backupset'
-- Consulta retorna:
backup_set_id
backup_set_uuid
-- Resultado desejado:
backup_set_id, backup_set_uuid
Você pode fazer isso com cursores ou inventar outra maluquice qualquer, mas não é nada elegante. Lendo um livro do Itzik Ben Gan eu vi uma abordagem bem elegante que ele propunha e passei a adotá-la em meus treinamentos e dicas.
A consulta que retorna o esperado pode ser escrita da seguinte forma:
SELECT STUFF(
(SELECT TOP 2
N',' + QUOTENAME(COLUMN_NAME) AS [text()]
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'backupset'
FOR XML PATH('')), 1, 1, N'')
go
Aqui você utiliza o FOR XML PATH('') para gerar um XML sem elemento por registro e usa a função text() para recuperar somente o texto do elemento, dispensando as tags que seriam o nome da coluna. Depois é só remover a primeira vírgula e pronto!
Gostou da solução? Eu sim... :-)
Aqui está a thread do MSDN para consulta: http://social.msdn.microsoft.com/Forums/pt-BR/transactsqlpt/thread/35db803c-44ce-4007-8cef-9b36801d86dc/?prof=required
[]s
Luciano Caixeta Moreira - {Luti Nimbus}
Chief Innovation Officer
Sr. Nimbus Serviços em Tecnologia Ltda
E-mail: luciano.moreira@srnimbus.com.br
Já vi muita pergunta em fóruns onde o pessoal vive tentando arranjar um jeito de mostrar uma série de registros em uma só coluna, separado por vírgula ou sei lá. Aproveitei uma thread que estava rolando no MSDN para usar de base para esse pequeno artigo...
O problema era pegar a consulta abaixo e retornar o resultado em somente uma linha:
USE MSDB
go
SELECT TOP 2 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'backupset'
-- Consulta retorna:
backup_set_id
backup_set_uuid
-- Resultado desejado:
backup_set_id, backup_set_uuid
Você pode fazer isso com cursores ou inventar outra maluquice qualquer, mas não é nada elegante. Lendo um livro do Itzik Ben Gan eu vi uma abordagem bem elegante que ele propunha e passei a adotá-la em meus treinamentos e dicas.
A consulta que retorna o esperado pode ser escrita da seguinte forma:
SELECT STUFF(
(SELECT TOP 2
N',' + QUOTENAME(COLUMN_NAME) AS [text()]
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'backupset'
FOR XML PATH('')), 1, 1, N'')
go
Aqui você utiliza o FOR XML PATH('') para gerar um XML sem elemento por registro e usa a função text() para recuperar somente o texto do elemento, dispensando as tags que seriam o nome da coluna. Depois é só remover a primeira vírgula e pronto!
Gostou da solução? Eu sim... :-)
Aqui está a thread do MSDN para consulta: http://social.msdn.microsoft.com/Forums/pt-BR/transactsqlpt/thread/35db803c-44ce-4007-8cef-9b36801d86dc/?prof=required
[]s
Luciano Caixeta Moreira - {Luti Nimbus}
Chief Innovation Officer
Sr. Nimbus Serviços em Tecnologia Ltda
E-mail: luciano.moreira@srnimbus.com.br
Marcadores:
Dicas e Truques,
SQL Server,
T-SQL,
XML
Assinar:
Postagens (Atom)

