sábado, 7 de agosto de 2010

Concatenar strings em registros diferentes - WM_Concat

Na sua empresa há uma tabela de Funcionários e outra de dependentes, conjuge, filhos, etc...) de cada funcionário. Há, portanto, duas tabelas: Funcionario( Func_ID, Nome, Dt_Nasc) e Dependente(Dep_ID, Func_ID, Nome, Relacao). É um tradicional relacionamento 1-N.

Como exemplo:

TABELA FUNCIONARIO
IDNOMEDT_NASC
1João25/12/1980
2Maria04/04/1987
3Paulo29/09/1984

TABELA DEPENDENTE
DEP_IDFUNC_IDNOMERELACAO
11Ana MariaConjuge
21Ana PaulaFilho(a)
31João JrFilho(a)
42CarlosConjuge
53PedroFilho(a)
63JuliaFilho(a)

Então, preparando uma festa de dia das crianças para os filhos do funcionário, alguém solicita um relatório com o nome do funcionário e o nome de todos seus filhos. Detalhe: todos em uma mesma coluna. Portanto, para atender à solicitação, teríamos:

RELATÓRIO DOS FILHOS
NOME DO FUNCIONÁRIOLISTA DE FILHOS(AS)
JoãoAna Paula, João Jr
Maria
PauloPedro, Julia

As tabelas de Funcionários e Dependentes podem ser criadas como views temporárias, apenas para uso nas queries de teste, pelo comando:

with funcionario as

(select 1 FUNC_ID, 'João' Nome, to_date('25/12/1980', 'dd/mm/yyyy') Dt_Nasc from dual union all
select 2 FUNC_ID, 'Maria' Nome, to_date('04/04/1987', 'dd/mm/yyyy') Dt_Nasc from dual union all
select 3 FUNC_ID, 'Paulo' Nome, to_date('29/09/1984', 'dd/mm/yyyy') Dt_Nasc from dual),
dependente as
(select 1 DEP_ID, 1 FUNC_ID, 'Ana Maria' Nome, 'Conjuge' Relacao from dual union all
select 2 DEP_ID, 1 FUNC_ID, 'Ana Paula' Nome, 'Filho(a)' Relacao from dual union all
select 3 DEP_ID, 1 FUNC_ID, 'João Jr' Nome, 'Filho(a)' Relacao from dual union all
select 4 DEP_ID, 2 FUNC_ID, 'Carlos' Nome, 'Conjuge' Relacao from dual union all
select 5 DEP_ID, 3 FUNC_ID, 'Pedro' Nome, 'Filho(a)' Relacao from dual union all
select 6 DEP_ID, 3 FUNC_ID, 'Julia' Nome, 'Filho(a)' Relacao from dual )


No Oracle há uma função não documentada, WM_CONCAT, que pode ser utilizada como uma função agregadora, da mesma forma que as habituais MAX, MIN, SUM e AVG. A query seria:

select f.nome, WM_CONCAT(d.nome)
  from funcionario f,
       dependente d
 where f.func_id = d.func_id
   and d.relacao = 'Filho(a)'
 group by f.nome;

Os valores são separados por vírgula. Caso seja necessário, a função REPLACE pode substituir a vírgula. eu usei para acrescentar um espaço após a vírgula, deste modo:

select f.nome, replace(WM_CONCAT(d.nome), ',', ', ')
  from funcionario f,
       dependente d
 where f.func_id = d.func_id
   and d.relacao = 'Filho(a)'
 group by f.nome;

Por último, uma palavra de precaução: como esta função não é documentada, a Oracle tem liberdade para numa próxima versão alterar o funcionamento ou simplesmente removê-la. Sendo assim, utilizá-la numa query para atender um demanda momentânea é seguro. Já utilizá-la em uma solução definitiva ou que deva rodar em várias versões de Oracle, é menos recomendável.

Nenhum comentário:

Postar um comentário