Eu sei que em época onde os ORMs estão cada vez mais espertos, é natural que o número de programadores com habilidade de escrever um bom SQL acabe diminuindo.

Mas não se engane: bons programadores também precisam saber SQL – mesmo que seja pra ler o que o ORM montou e aferir se a estratégia adotada foi a melhor.

Enfim, deixe-me ser mais objetivo.

Eu estava escrevendo um SQL no qual a minha fonte de dados provinha de duas tabelas distintas. Pra piorar a minha situação, eu precisava que os dados fossem apresentados sem repetição e ordenados.

Se eu fosse apurar cada tabela eu teria algo mais ou menos assim:

# Dados da tabela de vendas

select distinct
  produtos.codigo,
  produtos.nome
from
  vendas_itens
  join
    produtos
  on
    produtos.codigo = vendas_itens.produto
order by
  produtos.codigo
  produtos.nome
# Dados da tabela de doacoes

select distinct
  produtos.codigo,
  produtos.nome
from
  doacoes_itens
  join
    produtos
  on
    produtos.codigo = doacoes_itens.produto
order by
  produtos.codigo
  produtos.nome

Eu não queria gerar uma coleção e fazer isso tudo na unha. Eu queria mesmo era pegar isso tudo diretamente num único resultset. E agora?

Felizmente o Firebird 2.5 introduziu a possibilidade de fazer Select from Select. Isso é genial para o nosso caso, pois podemos fazer algo assim:

select distinct
  produtos.codigo,
  produtos.nome
from
  (
    select distinct
      vendas_itens.produto
    from
      vendas_itens

    union all

    select distinct
      doacoes_itens.produto
    from
      doacoes_itens
  ) dados
  join
    produtos
  on
    produtos.codigo = dados.produto
order by
  produtos.codigo,
  produtos.nome

Lindo! Agora temos a lista dos produtos vindos de duas fontes de dados, sem repetição e ordenados.

Este truque pode ser usado para as agragações e outras funções. Se você tentar usar um group by com um sum e um union all… não rola. Você terá que apelar pra técnica abaixo.

select
  produtos.codigo,
  produtos.nome
  sum(dados.quantidade)
from
  (
    select
      vendas_itens.produto,
      sum(vendas_itens.quantidade)
    from
      vendas_itens
    group by
      vendas_itens.produto

    union all

    select
      doacoes_itens.produto,
      sum(doacoes_itens.quantidade)
    from
      doacoes_itens
    group by
      doacoes_itens.produto
  ) dados
  join
    produtos
  on
    produtos.codigo = dados.produto
group by
  produtos.codigo,
  produtos.nome
order by
  produtos.codigo,
  produtos.nome

É isso aí! Espero que essa dica lhe ajude.