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é 🙂