Buscar K
Aparência
Aparência
Sem ligação, cada tabela de uma Aplicação responde só sobre si mesma: dá para somar vendas e contar clientes, mas não para saber quanto se vendeu no segmento varejo, porque essa pergunta precisa das duas tabelas. O modelo de dados é o conjunto das tabelas e das ligações entre elas, e a ligação é o caminho por onde o filtro de uma tabela chega à outra.
Você monta o modelo na aba Tabelas do editor da Aplicação. O passo a passo está em Tabelas e relacionamentos.
Toda ligação junta dois tipos de tabela. A tabela dimensão tem uma linha por coisa: um cliente, um produto, um dia. A tabela fato tem uma linha por acontecimento: uma venda, uma meta, um pedido, e repete o código do cliente ou do produto em muitas linhas.
O lado da dimensão é o Lado 1 da ligação, e o lado da fato é o Lado N. Um filtro na dimensão desce para a fato: filtrar o segmento na tabela de clientes muda o total de vendas sem que você configure nada no Widget de vendas.
A ligação tem dois valores de Cardinalidade na tela:
| Na tela | No YAML | O que faz |
|---|---|---|
| Um para muitos | ONE_TO_MANY | O filtro anda do Lado 1 para o Lado N. É o padrão |
| Um para um | ONE_TO_ONE | Os dois lados têm a chave única, e o filtro anda nos dois sentidos |
Só Um para um muda o comportamento. O YAML do Lumo CLI aceita também MANY_TO_ONE e MANY_TO_MANY, mas qualquer valor diferente de ONE_TO_ONE é gravado como um para muitos, com a direção dada por qual tabela está em cada lado. Escrever MANY_TO_MANY não cria uma ligação muitos para muitos.
Use Um para um quando as duas tabelas descrevem a mesma coisa com uma linha cada, como um cadastro de funcionário e uma tabela com dados complementares desse funcionário. Para muitos para muitos de verdade, como alunos e cursos, use uma tabela de ligação no meio (veja Tabelas e relacionamentos).
Se a chave do Lado 1 se repete, cada linha da fato casa com mais de uma linha da dimensão e a soma do outro lado infla, sem erro nenhum. Um cliente cadastrado duas vezes conta as vendas dele em dobro.
O editor confere o dado quando você mexe numa ligação e avisa: "{chave} se repete em {tabela}: N valores aparecem mais de uma vez, até M×. A soma do outro lado pode inflar." O aviso não impede salvar, para não travar Aplicações que já existem. Corrija a chave na origem, no HorusDW, ou use uma chave composta com mais de uma coluna.
Vendas e Metas parecem combinar: as duas têm vendedor e mês. Mas nenhuma das duas tem a chave única, então nenhuma pode ser o Lado 1. Ligadas direto, cada venda casa com cada meta que tenha a mesma chave, e o resultado é o produto das duas: com 1.000 vendas e 500 metas de um vendedor, a consulta passa por 500.000 combinações e os totais saem multiplicados. Isso se chama explosão cartesiana.
Execute cada aba para ver o problema e entender por que o JOIN direto entre fatos multiplica os valores.
A saída é uma dimensão compartilhada. Vendas e Metas apontam cada uma para o Calendário e para o Vendedor, e as duas passam a se comparar por esse caminho, cada uma no seu grão:
Quando um Widget usa medidas de duas fatos, o Lumo faz uma consulta para cada fato e junta os resultados pelas dimensões do Widget. Por isso SUM([Vendas]."VALOR") / SUM([Metas]."VALOR_META") dá o percentual certo de atingimento por vendedor ou por mês.
Use no Widget a coluna da dimensão, não a da fato. Calendário.DATA serve para Vendas e para Metas; Vendas.DATA_VENDA só existe para Vendas, e as metas ficariam de fora.
Se um Widget cruza duas fatos e usa uma dimensão que só uma delas alcança, o mesmo registro aparece em mais de uma linha. Suponha que Produto se liga a Vendas e não a Metas, porque a meta é por vendedor e mês. Um relatório com Vendedor, Produto, vendas e meta sai assim:
| Vendedor | Produto | Vendas | Meta |
|---|---|---|---|
| João | Notebook | R$ 5.000 | R$ 0 |
| João | Monitor | R$ 3.200 | R$ 0 |
| João | (vazio) | R$ 0 | R$ 8.000 |
A consulta de Metas não tem como preencher Produto, e a meta de João fica numa linha sem produto. Nenhum modelo resolve isso, porque a meta não existe por produto. Ao cruzar fatos, use só as dimensões que todas alcançam (aqui, Vendedor e Calendário).
Produto so existe em Vendas, nao em Metas. Veja o que acontece ao inclui-lo no relatorio e como resolver.
Calendário e Empresa se ligam a Faturamento, e não uma à outra. Um filtro de março no Calendário só limita a lista de empresas quando o Widget também usa uma coluna de Faturamento: é a fato que liga as duas. Um Widget que lista só Empresa.Nome mostra todas as empresas, com ou sem filtro de data.
O mesmo vale para o filtro fixo de uma tabela fato (o Filtros Pré Aplicados da aba Tabelas): ele só entra na consulta quando o Widget usa alguma coluna daquela fato. Para um recorte que valha sempre, ponha o filtro na dimensão. Os tipos de filtro estão em Filtros.
Uma fato costuma ter mais de uma data: a nota tem emissão e entrega, a oportunidade tem abertura, ganho e perda. Em vez de um Calendário para cada data, ligue o mesmo Calendário à fato por mais de uma chave. A primeira chave é a Padrão, usada em todo filtro e agrupamento; as outras ficam como Secundário (use) e só valem numa expressão que pede por elas com use():
use([Calendário], [Faturamento].DATA_ENTREGA) SUM([Faturamento]."VALOR")O cadastro das chaves está em Tabelas e relacionamentos, e a sintaxe, em Linguagem de expressões.
Outra saída para Vendas e Metas é juntar as duas numa tabela fato só, no HorusETL, com uma coluna que diz a origem e as colunas de cada uma preenchidas com zero ou vazio na outra:
SELECT 'Venda' AS FATO, DATA, PRODUTO, VALOR AS VALOR_VENDA, 0 AS VALOR_META FROM VENDAS
UNION ALL
SELECT 'Meta' AS FATO, DATA, PRODUTO, 0 AS VALOR_VENDA, META AS VALOR_META FROM METASO modelo fica mais simples e o cálculo entre as duas é uma conta na mesma tabela. O custo é a flexibilidade: cada fonte nova muda a tabela, e as colunas de uma origem ficam vazias nas linhas da outra. O nó de união do ETL está na referência do HorusETL.
Veja como unificar Vendas e Metas em uma unica tabela e calcular metricas cruzadas sem explosao cartesiana.
| Caminho | Bom para | Custa |
|---|---|---|
| Dimensões compartilhadas | Modelo que cresce, cada fato com as suas colunas | Manter as tabelas dimensão, como o Calendário |
| Tabela fato só | Fatos parecidas, de grãos diferentes, com cálculo entre elas | Refazer a tabela a cada fonte nova |
Na tela, o modelo se monta na aba Tabelas (Tabelas e relacionamentos). As expressões que cruzam fatos estão em Linguagem de expressões, e o caso de várias datas e granularidades, em Calendário e filtros por data.
Pelo Lumo CLI
Tabelas e relacionamentos da Aplicação também podem ser versionados em YAML, com relationshipType e ignoreTime. Veja a referência de app.