Oi! Seja bem-vindo!

Hoje nosso assunto é ROW CONSTRUCTOR no SQL Server, um recurso que quando aplicado, torna o código transact-sql mais legível e de fácil manutenção.

O nome, “ROW CONSTRUCTOR”, honestamente não ajuda nada no entendimento desse troço… por isso essa técnica também é conhecida informalmente como “select from texto”, “select from values” e outros nomes que nem sei…. Construtor de linhas (no português) acho que também não ajuda.

Apesar da dificuldade do nome, trata-se de uma técnica interessante e fácil de usar, como veremos a seguir:

ROW CONSTRUCTOR no SQL Server

Até um tempo atrás, se quiséssemos transformar um conjunto de textos em um resultset único, a alternativa era executar uma série de “SELECTs com UNION ALL”, como no exemplo abaixo:

select 'Pessoa 1'
union all select 'Pessoa 2'
union all select 'Pessoa 3'

No geral, o código acima tem difícil leitura e muita digitação, devido a repetição dos comandos. Para resolver o problema, foram lançadas duas tecnologias, ROW CONSTRUCTOR no SQL2008 e String Split no SQL20016.

ROW CONSTRUCTOR

A primeira tecnologia, é o tema principal desse artigo, o “ROW CONSTRUCTOR”. Essa técnica ficou conhecida para utilização com INSERTs (que mostrarei mais adiante), mas também é possível usar com SELECTs. Muitos argumentam que no exemplo abaixo, a legibilidade é melhor do que utilizando UNION ALL:

select 
	* 
from (values ('Pessoa 1'), ('Pessoa 2'), ('Pessoa 3')) as rc(valores)

Se você pensou, nossa, com ROW CONSTRUCTOR ficou tão ruim quanto com union all, sou obrigado a dar o braço a torcer e concordar contigo… kkkkk Porém, isso ocorre quando estamos selecionando apenas uma coluna, para inúmeras colunas e com a endentação correta, talvez você goste mais dessa tecnologia, vamos ver :):

select 
	*
from (
	values 
		('Pessoa 1', '(011) 9999-0001'),
		('Pessoa 2', '(021) 9999-0001'),
		('Pessoa 3', '(041) 9999-0001')
) as tabela(nome, telefone)

E ai, melhorou?

String Split

A segunda tecnologia para fazer “select de textos” é o String Split. Apesar desse recurso nada ter haver com “ROW CONSTRUCTOR”, coloquei o exemplo aqui porque quando tratamos de uma coluna única, me parece que o código fica bastante amigável. Veja abaixo:

select 
	* 
from string_split('Pessoa 1,Pessoa 2,Pessoa 3', ',') 

O que acha?

ROW CONSTRUCTOR para INSERTs

Bem, se você ainda não gostou do ROW CONSTRUCTOR… acho que pelo menos esse exemplo vai te agradar. A partir do SQL 2008, quando essa tecnologia foi introduzida, ao invés de fazer isso:

-- INSERT tradicional
INSERT into #amigos values (1, 'Pessoa 1')
INSERT into #amigos values (2, 'Pessoa 2')

Você pode fazer isso:

-- INSERT row-constructor
INSERT into #amigos values 
	(3, 'Pessoa 3'), 
	(4, 'Pessoa 4')

Particularmente uso bastante o ROW CONSTRUCTOR em meus scripts de carga de dados, porque é visível que os arquivos ficam menores em tamanho e melhores em legibilidade.

Outro ponto interessante, é que o INSERT usando ROW CONSTRUCTOR é mais rápido que INSERTSs individuais, porque trata-se de uma só transação, ao invés de múltiplas. É claro que podemos encapsular os INSERTS em uma transação única a resolver essa limitação, mas acho interessante o fato do benefício ser automático usando ROW CONSTRUCTOR.

Script do vídeo

Por fim, aqui vai o script utilizado no vídeo de hoje:


------------------------------------------------------------------
-- Row Constructor & Select from texto
------------------------------------------------------------------
--------------------------------------------------
-- Row constructor em select
--------------------------------------------------
/* Tarefa: Transformar texto em resultset
'Pessoa 1'
'Pessoa 2'
'Pessoa 3'
*/
-- Resultset único com union
select 'Pessoa 1'
union all select 'Pessoa 2'
union all select 'Pessoa 3'

-- Multiplos resultsets
select 'Pessoa 1'
select 'Pessoa 2'
select 'Pessoa 3'

-- Row constructor
select 
	* 
from (values ('Pessoa 1'), ('Pessoa 2'), ('Pessoa 3')) as rc(valores)


-- String_split
select 
	* 
from string_split('Pessoa 1,Pessoa 2,Pessoa 3', ',')


-- Row constructor - multiplas colunas & ID automático
select 
	*
from (
	values 
		('Pessoa 1', '(011) 9999-0001'),
		('Pessoa 2', '(021) 9999-0001'),
		('Pessoa 3', '(041) 9999-0001')
) as tabela(nome, telefone)


--------------------------------------------------
-- Row constructor no INSERT
--------------------------------------------------
-- Tabela de testes
create table #amigos (id int, nome varchar(10))

-- Insert tradicional
insert into #amigos values (1, 'Pessoa 1')
insert into #amigos values (2, 'Pessoa 2')

-- Insert row-constructor
insert into #amigos values 
	(3, 'Pessoa 3'), 
	(4, 'Pessoa 4')


--------------------------------------------------
-- Excluir dados de teste
--------------------------------------------------
if object_id('tempdb.dbo.#amigos') is not null drop table #amigos

CONCLUSÃO

Apresentei a você o ROW CONSTRUCTOR, seus antecessores (UNION ALL) e talvez predecessores em alguns casos (STRING_SPLIT). Particularmente gosto dos três dependendo do caso, então acho que não há um vencedor e fique mais a critério do freguês escolher qual usar, certo?

Não sei qual das técnicas seria a vencedora em termos de performance, talvez isso dê outro artigo…. 🙂 Me diga o que acha e qual você mais gosta?

Abraço do seu amigo Josué 🙂

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *