Share via


Orientação de relacionamento muitos-para-muitos

Este artigo destina-se a você como um modelador de dados que trabalha com o Power BI Desktop. Ele descreve três diferentes cenários de modelagem muitos-para-muitos. Ele também fornece orientação sobre como projetar com sucesso para eles em seus modelos.

Nota

Uma introdução às relações de modelo não é abordada neste artigo. Se você não estiver completamente familiarizado com relacionamentos, suas propriedades ou como configurá-los, recomendamos que leia primeiro o artigo Relações de modelo no Power BI Desktop .

Também é importante que você tenha uma compreensão do design do esquema de estrelas. Para obter mais informações, consulte Compreender o esquema em estrela e a importância para o Power BI.

Existem, de facto, três cenários muitos-para-muitos. Eles podem ocorrer quando você é obrigado a:

Nota

O Power BI agora oferece suporte nativo a relacionamentos muitos-para-muitos. Para obter mais informações, consulte Aplicar muitas e muitas relações no Power BI Desktop.

Relacionar muitas para muitas dimensões

Vamos considerar o primeiro tipo de cenário muitos-para-muitos com um exemplo. O cenário clássico relaciona duas entidades: clientes bancários e contas bancárias. Considere que os clientes podem ter várias contas e as contas podem ter vários clientes. Quando uma conta tem vários clientes, eles são comumente chamados de titulares de contas conjuntas.

Modelar essas entidades é simples. Uma tabela de tipo de dimensão armazena contas e outra tabela de tipo de dimensão armazena clientes. Como é característico das tabelas de tipo de dimensão, há uma coluna ID em cada tabela. Para modelar a relação entre as duas tabelas, é necessária uma terceira tabela. Esta tabela é comumente referida como uma tabela de ponte. Neste exemplo, sua finalidade é armazenar uma linha para cada associação de conta de cliente. Curiosamente, quando essa tabela contém apenas colunas de ID, ela é chamada de tabela de fatos sem fatos.

Aqui está um diagrama de modelo simplista das três tabelas.

Diagram showing a model containing three tables. The design is described in the following paragraph.

A primeira tabela chama-se Conta e contém duas colunas: AccountID e Account. A segunda tabela é chamada AccountCustomer e contém duas colunas: AccountID e CustomerID. A terceira tabela é chamada Cliente e contém duas colunas: CustomerID e Customer. Não existem relações entre nenhuma das tabelas.

Duas relações um-para-muitos são adicionadas para relacionar as tabelas. Aqui está um diagrama de modelo atualizado das tabelas relacionadas. Uma tabela de tipo de fato chamada Transação foi adicionada. Regista as transações da conta. A tabela de ponte e todas as colunas ID foram ocultadas.

Diagram showing that the model now contains four tables. One-to-many relationships have been added to relate all tables.

Para ajudar a descrever como funciona a propagação do filtro de relacionamento, o diagrama de modelo foi modificado para revelar as linhas da tabela.

Nota

Não é possível exibir linhas de tabela no diagrama de modelo do Power BI Desktop. É feito neste artigo para apoiar a discussão com exemplos claros.

Diagram showing that the model now reveals the table rows. The row details for the four tables are described in the following paragraph.

Os detalhes da linha para as quatro tabelas são descritos na seguinte lista com marcadores:

  • A tabela Conta tem duas linhas:
    • AccountID 1 é para Account-01
    • AccountID 2 é para Account-02
  • A tabela Cliente tem duas linhas:
    • CustomerID 91 é para Customer-91
    • CustomerID 92 é para Customer-92
  • A tabela AccountCustomer tem três linhas:
    • AccountID 1 está associado a CustomerID 91
    • AccountID 1 está associado a CustomerID 92
    • AccountID 2 está associado a CustomerID 92
  • A tabela Transação tem três linhas:
    • Data: 1 de janeiro de 2019, AccountID 1, Montante 100
    • Data: 2 de fevereiro de 2019, AccountID 2, Montante 200
    • Data: 3 de março de 2019, AccountID 1, Montante -25

Vamos ver o que acontece quando o modelo é consultado.

Abaixo estão dois elementos visuais que resumem a coluna Valor da tabela Transação . Os primeiros grupos visuais por conta e, portanto, a soma das colunas Valor representa o saldo da conta. O segundo grupo visual por cliente e, portanto, a soma das colunas Valor representa o saldo do cliente.

Diagram showing two report visuals sitting side by side. The visuals are described in the following paragraph.

O primeiro visual intitula-se Saldo da Conta e tem duas colunas: Conta e Montante. Ele exibe o seguinte resultado:

  • O valor do saldo da Conta-01 é 75
  • O valor do saldo da Conta-02 é de 200
  • O total é de 275

O segundo visual intitula-se Saldo do Cliente e tem duas colunas: Cliente e Montante. Ele exibe o seguinte resultado:

  • O valor do saldo do cliente-91 é de 275
  • O valor do saldo do cliente-92 é de 275
  • O total é de 275

Uma rápida olhada nas linhas da tabela e no visual do Saldo da Conta revela que o resultado está correto, para cada conta e o valor total. Isso ocorre porque cada agrupamento de conta resulta em uma propagação de filtro para a tabela Transação dessa conta.

No entanto, algo não parece correto com o visual do Saldo do cliente. Cada cliente no visual Saldo do Cliente tem o mesmo saldo que o saldo total. Este resultado só poderia ser correto se cada cliente fosse um titular conjunto de conta de cada conta. Não é o caso neste exemplo. O problema está relacionado à propagação do filtro. Não está fluindo até a tabela Transação .

Siga as instruções do filtro de relacionamento da tabela Cliente para a tabela Transação . Deve ser evidente que a relação entre a tabela Account e AccountCustomer está se propagando na direção errada. A direção do filtro para essa relação deve ser definida como Both.

Diagram showing that the model has been updated. It now filters in both directions.

Diagram showing the same two report visuals sitting side by side. The first visual has not changed, while the second visual has.

Como esperado, não houve alteração no visual do Saldo da Conta.

No entanto, os visuais do Saldo do Cliente agora exibem o seguinte resultado:

  • O valor do saldo do cliente-91 é 75
  • O valor do saldo do cliente-92 é de 275
  • O total é de 275

O visual Saldo do Cliente agora exibe um resultado correto. Siga as instruções do filtro por si mesmo e veja como os saldos dos clientes foram calculados. Além disso, entenda que o total visual significa todos os clientes.

Alguém não familiarizado com as relações do modelo pode concluir que o resultado está incorreto. Eles podem perguntar: Por que o saldo total para Customer-91 e Customer-92 não é igual a 350 (75 + 275)?

A resposta à sua pergunta está em compreender a relação muitos-para-muitos. Cada saldo de cliente pode representar a adição de vários saldos de conta e, portanto, os saldos de clientes não são aditivos.

Relacionar orientações de muitas para muitas dimensões

Quando você tem uma relação muitos-para-muitos entre tabelas de tipo de dimensão, fornecemos as seguintes orientações:

  • Adicione cada entidade relacionada a muitos para muitos como uma tabela modelo, garantindo que ela tenha uma coluna de identificador exclusivo (ID)
  • Adicionar uma tabela de ponte para armazenar entidades associadas
  • Criar relações um-para-muitos entre as três tabelas
  • Configure uma relação bidirecional para permitir que a propagação do filtro continue para as tabelas de tipo de fato
  • Quando não for apropriado ter valores de ID ausentes, defina a propriedade Is Nullable das colunas ID como FALSE — a atualização de dados falhará se os valores ausentes forem originados
  • Ocultar a tabela de ponte (a menos que contenha colunas ou medidas adicionais necessárias para a geração de relatórios)
  • Ocultar quaisquer colunas de ID que não sejam adequadas para relatórios (por exemplo, quando os IDs são chaves substitutas)
  • Se fizer sentido deixar uma coluna ID visível, certifique-se de que está no diapositivo "um" da relação — oculte sempre a coluna lateral "muitos". Isso resulta no melhor desempenho do filtro.
  • Para evitar confusão ou má interpretação, comunique explicações aos usuários do relatório — você pode adicionar descrições com caixas de texto ou dicas de ferramentas de cabeçalho visual

Não recomendamos que você relacione tabelas de tipo de dimensão muitos-para-muitos diretamente. Essa abordagem de design requer a configuração de um relacionamento com uma cardinalidade muitos-para-muitos. Conceitualmente isso pode ser alcançado, mas implica que as colunas relacionadas conterão valores duplicados. É uma prática de design bem aceita, no entanto, que as tabelas de tipo de dimensão tenham uma coluna ID. As tabelas de tipo de dimensão devem sempre usar a coluna ID como o lado "um" de uma relação.

Relacione muitos para muitos fatos

O segundo tipo de cenário muitos-para-muitos envolve a relação de duas tabelas de tipo de fato. Duas tabelas de fatos podem ser relacionadas diretamente. Esta técnica de design pode ser útil para uma exploração de dados rápida e simples. No entanto, e para ser claro, geralmente não recomendamos essa abordagem de design. Explicaremos o porquê mais adiante nesta seção.

Vamos considerar um exemplo que envolve duas tabelas de tipo de fato: Ordem e Cumprimento. A tabela Order contém uma linha por linha de ordem e a tabela Fulfillment pode conter zero ou mais linhas por linha de ordem. As linhas na tabela Ordem representam ordens de venda. As linhas na tabela Fulfillment representam itens de ordem que foram enviados. Uma relação muitos-para-muitos relaciona as duas colunas OrderID, com propagação de filtro somente da tabela Order (Order filters Fulfillment).

Diagram showing a model containing two tables: Order and Fulfillment.

A cardinalidade da relação é definida como muitos-para-muitos para dar suporte ao armazenamento de valores OrderID duplicados em ambas as tabelas. Na tabela Order, valores OrderID duplicados podem existir porque um pedido pode ter várias linhas. Na tabela Fulfillment, valores duplicados de OrderID podem existir porque os pedidos podem ter várias linhas e as linhas de ordem podem ser atendidas por muitas remessas.

Vamos agora dar uma olhada nas linhas da tabela. Na tabela Fulfillment, observe que as linhas de pedidos podem ser atendidas por várias remessas. (A ausência de uma linha de ordem significa que a ordem ainda não foi cumprida.)

Diagram showing that the model now reveals the table rows. The row details for the two tables are described in the following paragraph.

Os detalhes da linha para as duas tabelas são descritos na seguinte lista com marcadores:

  • A tabela Ordem tem cinco linhas:
    • Data do pedido: 1 de janeiro de 2019, OrderID 1, OrderLine 1, ProductID Prod-A, OrderQuantity 5, Sales 50
    • Data do pedido: 1 de janeiro de 2019, OrderID 1, OrderLine 2, ProductID Prod-B, OrderQuantity 10, Sales 80
    • Data do pedido: 2 de fevereiro de 2019, OrderID 2, OrderLine 1, ProductID Prod-B, OrderQuantity 5, Sales 40
    • Data do pedido: 2 de fevereiro de 2019, OrderID 2, OrderLine 2, ProductID Prod-C, OrderQuantity 1, Sales 20
    • OrderDate março 3 2019, OrderID 3, OrderLine 1, ProductID Prod-C, OrderQuantity 5, Sales 100
  • A tabela Fulfillment tem quatro linhas:
    • FulfillmentDate 1 de janeiro de 2019, FulfillmentID 50, OrderID 1, OrderLine 1, FulfillmentQuantity 2
    • FulfillmentDate 2 de fevereiro de 2019, FulfillmentID 51, OrderID 2, OrderLine 1, FulfillmentQuantity 5
    • FulfillmentDate 2 de fevereiro de 2019, FulfillmentID 52, OrderID 1, OrderLine 1, FulfillmentQuantity 3
    • FulfillmentDate 1 de janeiro de 2019, FulfillmentID 53, OrderID 1, OrderLine 2, FulfillmentQuantity 10

Vamos ver o que acontece quando o modelo é consultado. Aqui está um visual de tabela comparando as quantidades de pedido e cumprimento pela coluna Order ID da tabela de pedidos.

Diagram showing a table visual with three columns: OrderID, OrderQuantity, and FulfillmentQuantity.

O visual apresenta um resultado preciso. No entanto, a utilidade do modelo é limitada — você só pode filtrar ou agrupar pela coluna Order ID da tabela Order.

Relacione a orientação de muitos para muitos fatos

Geralmente, não recomendamos relacionar duas tabelas de tipo de fato diretamente usando cardinalidade muitos-para-muitos. O principal motivo é porque o modelo não fornecerá flexibilidade nas maneiras como você relata, visual, filtro ou grupo. No exemplo, só é possível que os elementos visuais filtrem ou agrupem pela coluna Order ID da tabela Order. Uma razão adicional está relacionada com a qualidade dos seus dados. Se os seus dados tiverem problemas de integridade, é possível que algumas linhas possam ser omitidas durante a consulta devido à natureza da relação limitada. Para obter mais informações, consulte Relações de modelo no Power BI Desktop (Avaliação de relacionamento).

Em vez de relacionar tabelas de tipos de fatos diretamente, recomendamos que você adote os princípios de design do Star Schema . Você faz isso adicionando tabelas de tipo de dimensão. Em seguida, as tabelas de tipo de dimensão se relacionam com as tabelas de tipo de fato usando relações um-para-muitos. Essa abordagem de design é robusta, pois oferece opções flexíveis de relatórios. Ele permite filtrar ou agrupar usando qualquer uma das colunas de tipo de dimensão e resumir qualquer tabela de tipo de fato relacionada.

Vamos considerar uma solução melhor.

Diagram showing a model includes six tables: OrderLine, OrderDate, Order, Fulfillment, Product, and FulfillmentDate.

Observe as seguintes alterações de design:

  • O modelo agora tem quatro tabelas adicionais: OrderLine, OrderDate, Product e FulfillmentDate
  • As quatro tabelas adicionais são todas tabelas de tipo de dimensão, e as relações um-para-muitos relacionam essas tabelas com as tabelas de tipo de fato
  • A tabela OrderLine contém uma coluna OrderLineID, que representa o valor OrderID multiplicado por 100, mais o valor OrderLine — um identificador exclusivo para cada linha de ordem
  • As tabelas Order and Fulfillment agora contêm uma coluna OrderLineID e não contêm mais as colunas OrderID e OrderLine
  • A tabela Fulfillment agora contém as colunas OrderDate e ProductID
  • A tabela FulfillmentDate refere-se apenas à tabela Fulfillment
  • Todas as colunas de identificador exclusivo estão ocultas

Dedicar um tempo para aplicar os princípios de design do esquema em estrela oferece os seguintes benefícios:

  • Os visuais de relatório podem filtrar ou agrupar por qualquer coluna visível das tabelas de tipo de dimensão
  • Os visuais do relatório podem resumir qualquer coluna visível das tabelas de tipo de fato
  • Os filtros aplicados às tabelas OrderLine, OrderDate ou Product serão propagados para ambas as tabelas de tipo de fato
  • Todas as relações são um-para-muitos, e cada relação é uma relação regular. Os problemas de integridade de dados não serão mascarados. Para obter mais informações, consulte Relações de modelo no Power BI Desktop (Avaliação de relacionamento).

Relacione fatos de grãos mais altos

Este cenário muitos-para-muitos é muito diferente dos outros dois já descritos neste artigo.

Vamos considerar um exemplo envolvendo quatro tabelas: Data, Vendas, Produto e Destino. A Data e o Produto são tabelas de tipo de dimensão, e as relações um-para-muitos relacionam-se cada uma com a tabela de tipo de fato Vendas. Até agora, representa um bom design de esquema de estrela. A tabela Target , no entanto, ainda não está relacionada com as outras tabelas.

Diagram showing a model including four tables: Date, Sales, Product, and Target.

A tabela Target contém três colunas: Category, TargetQuantity e TargetYear. As linhas da tabela revelam uma granularidade de ano e categoria de produto. Em outras palavras, as metas – usadas para medir o desempenho de vendas – são definidas a cada ano para cada categoria de produto.

Diagram showing the Target table has three columns: TargetYear, Category, and TargetQuantity.

Como a tabela Target armazena dados em um nível mais alto do que as tabelas de tipo de dimensão, uma relação um-para-muitos não pode ser criada. Bem, isso é verdade para apenas um dos relacionamentos. Vamos explorar como a tabela Target pode ser relacionada às tabelas de tipo de dimensão.

Relacione períodos de tempo de grãos mais altos

Uma relação entre as tabelas Data e Destino deve ser uma relação um-para-muitos. Isso ocorre porque os valores da coluna TargetYear são datas. Neste exemplo, cada valor de coluna TargetYear é a primeira data do ano de destino.

Gorjeta

Ao armazenar fatos em uma granularidade de tempo maior do que o dia, defina o tipo de dados da coluna como Data (ou Número inteiro, se estiver usando chaves de data). Na coluna, armazene um valor que represente o primeiro dia do período de tempo. Por exemplo, um período de um ano é registrado como 1º de janeiro do ano e um período de um mês é registrado como o primeiro dia desse mês.

No entanto, é necessário ter cuidado para garantir que os filtros de nível de mês ou data produzam um resultado significativo. Sem qualquer lógica de cálculo especial, os visuais do relatório podem informar que as datas-alvo são literalmente o primeiro dia de cada ano. Todos os outros dias — e todos os meses, exceto janeiro — resumirão a quantidade-alvo como BLANK.

O visual da matriz a seguir mostra o que acontece quando o usuário do relatório detalha de um ano em seus meses. O visual está resumindo a coluna TargetQuantity . (O A opção Mostrar itens sem dados foi habilitada para as linhas da matriz.)

Diagram showing a matrix visual revealing the year 2020 target quantity as 270.

Para evitar esse comportamento, recomendamos que você controle a sumarização de seus dados de fato usando medidas. Uma maneira de controlar o resumo é retornar BLANK quando períodos de tempo de nível inferior são consultados. Outra maneira — definida com algum DAX sofisticado — é distribuir valores em períodos de tempo de nível inferior.

Considere a seguinte definição de medida que usa a função ISFILTERED DAX. Ele só retorna um valor quando as colunas Data ou Mês não são filtradas.

Target Quantity =
IF(
    NOT ISFILTERED('Date'[Date])
        && NOT ISFILTERED('Date'[Month]),
    SUM(Target[TargetQuantity])
)

O visual da matriz a seguir agora usa a medida Quantidade Alvo . Mostra que todas as quantidades-alvo mensais estão EM BRANCO.

Diagram showing a matrix visual revealing the year 2020 target quantity as 270 with blank monthly values.

Relacionar grãos mais altos (sem data)

Uma abordagem de design diferente é necessária ao relacionar uma coluna sem data de uma tabela de tipo de dimensão com uma tabela de tipo de fato (e ela está em um grão mais alto do que a tabela de tipo de dimensão).

As colunas Categoria (das tabelas Produto e Destino ) contêm valores duplicados. Portanto, não há "um" para uma relação um-para-muitos. Nesse caso, você precisará criar um relacionamento muitos-para-muitos. A relação deve propagar filtros em uma única direção, da tabela de tipo de dimensão para a tabela de tipo de fato.

Diagram showing a model of the Target and Product tables. A many-to-many relationship relates the two tables.

Vamos agora dar uma olhada nas linhas da tabela.

Diagram showing a model containing two tables: Target and Product. A many-to-many relationship relates the two Category columns.

Na tabela Target, há quatro linhas: duas linhas para cada ano-alvo (2019 e 2020) e duas categorias (Vestuário e Acessórios). Na tabela Produtos, há três produtos. Dois pertencem à categoria de vestuário e um pertence à categoria de acessórios. Uma das cores da roupa é verde, e as duas restantes são azuis.

Um agrupamento visual de tabela pela coluna Categoria da tabela Produto produz o seguinte resultado.

Diagram showing a table visual with two columns: Category and TargetQuantity. Accessories is 60, Clothing is 40, and the total is 100.

Este visual produz o resultado correto. Vamos agora considerar o que acontece quando a coluna Cor da tabela Produto é usada para agrupar a quantidade de destino.

Diagram showing a table visual with two columns: Color and TargetQuantity. Blue is 100, Green is 40, and the total is 100.

O visual produz uma deturpação dos dados. O que está a acontecer aqui?

Um filtro na coluna Cor da tabela Produto resulta em duas linhas. Uma das linhas é para a categoria Vestuário, e a outra é para a categoria Acessórios. Esses dois valores de categoria são propagados como filtros para a tabela Target . Em outras palavras, como a cor azul é usada por produtos de duas categorias, essas categorias são usadas para filtrar os alvos.

Para evitar esse comportamento, conforme descrito anteriormente, recomendamos que você controle o resumo dos dados de fatos usando medidas.

Considere a seguinte definição de medida. Observe que todas as colunas da tabela Produto que estão abaixo do nível de categoria são testadas para filtros.

Target Quantity =
IF(
    NOT ISFILTERED('Product'[ProductID])
        && NOT ISFILTERED('Product'[Product])
        && NOT ISFILTERED('Product'[Color]),
    SUM(Target[TargetQuantity])
)

O visual da tabela a seguir agora usa a medida Quantidade Alvo . Ele mostra que todas as quantidades de destino de cor estão BLANK.

Diagram showing a table visual with two columns: Color and TargetQuantity. Blue is BLANK, Green is BLANK, and the total is 100.

O design final do modelo tem a seguinte aparência.

Diagram showing a model with Date and Target tables related with a one-to-many relationship.

Relacione a orientação de fatos de grãos mais altos

Quando você precisa relacionar uma tabela de tipo de dimensão a uma tabela de tipo de fato, e a tabela de tipo de fato armazena linhas em um grão mais alto do que as linhas de tabela de tipo de dimensão, fornecemos as seguintes orientações:

  • Para datas de fatos de grãos mais altas:
    • Na tabela de tipo de fato, armazene a primeira data do período de tempo
    • Criar uma relação um-para-muitos entre a tabela de data e a tabela de tipo de fato
  • Para outros fatos de grãos superiores:
    • Criar uma relação muitos-para-muitos entre a tabela de tipo de dimensão e a tabela de tipo de fato
  • Para ambos os tipos:
    • Controle a sumarização com lógica de medida — retorna BLANK quando colunas de tipo de dimensão de nível inferior são usadas para filtrar ou agrupar
    • Ocultar colunas de tabela de tipo de fato resumidas — dessa forma, apenas medidas podem ser usadas para resumir a tabela de tipo de fato

Para obter mais informações relacionadas a este artigo, confira os seguintes recursos: