Chama-se Entity-Attribute-Value (também às vezes 'pares nome-valor') e é um caso clássico de "um pino redondo em um buraco quadrado" quando as pessoas usam o padrão EAV em um banco de dados relacional.
Aqui está uma lista de por que você não deve usar o EAV:
- Você não pode usar tipos de dados. Não importa se o valor é uma data, um número ou dinheiro (decimal). Sempre será coagido a varchar. Isso pode ser qualquer coisa, desde um pequeno problema de desempenho até uma enorme dor de barriga (já teve que perseguir uma variação de um centavo em um relatório mensal de roll-up?).
- Você não pode (facilmente) impor restrições. Requer uma quantidade ridícula de código para impor "Todo mundo precisa ter uma altura entre 0 e 3 metros" ou "A idade não deve ser nula e> = 0", em oposição às 1-2 linhas em que cada uma dessas restrições seria em um sistema adequadamente modelado.
- Relacionado ao acima, você não pode garantir facilmente que obtém as informações necessárias para cada cliente (a idade pode estar faltando em um e a próxima pode estar perdendo a altura etc.). Você pode fazer isso, mas é muito mais difícil do que isso
SELECT height, weight, age FROM Client where height is null or weight is null
.
- Relacionado novamente, os dados duplicados são muito mais difíceis de detectar (o que acontece se eles fornecerem duas idades para um cliente? A eliminação dos dados EAV, como abaixo, fornecerá duas linhas de resultados se você tiver um atributo duplicado. Se um cliente possui duas entradas separadas para dois atributos, você obterá quatro linhas da consulta abaixo).
- Você nem pode garantir que os nomes dos atributos sejam consistentes. "Age_yr" pode se tornar "AGE_IN_YEARS" ou "age". (É certo que isso é menos problemático quando você recebe uma extração do que quando as pessoas estão inserindo dados, mas ainda assim.)
- Qualquer tipo de consulta não trivial é um desastre completo. Para relacionalizar um sistema EAV de três atributos para que você possa consultá-lo de forma racional, são necessárias três junções da tabela EAV.
Comparar:
SELECT cID.ID AS [ID], cH.Value AS [Height], cW.Value AS [Weight], cA.Value AS [Age]
FROM (SELECT DISTINCT ID FROM Client) cID
LEFT OUTER JOIN
Client cW ON cID.ID = cW.ID AND cW.Metric = "Wt_kg"
LEFT OUTER JOIN
Client cH ON cID.ID = cH.ID AND cW.Metric = "Ht_cm"
LEFT OUTER JOIN
Client cA ON cID.ID = cA.ID AND cW.Metric = "Age_yr"
Para:
SELECT c.ID, c.Ht_cm, c.Wt_kg, c.Age_yr
FROM Client c
Aqui está uma lista (muito curta) de quando você deve usar o EAV:
- Quando não há absolutamente nenhuma maneira de contornar isso e você precisa oferecer suporte a dados sem esquema no seu banco de dados.
- Quando você só precisa armazenar "coisas" e não espera precisar de uma forma mais estruturada. Cuidado, porém, o monstro chamado "requisitos em mudança".
Eu sei que eu só passei todo este post detalhando por EAV é uma idéia terrível na maioria dos casos - mas não são poucos os casos onde é necessária / inevitável. no entanto, na maioria das vezes (incluindo o exemplo acima), será muito mais complicado do que vale a pena. Se você precisa de um amplo suporte para entrada de dados do tipo EAV, deve armazená-los em um sistema de valores-chave, por exemplo, Hadoop / HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB.
Valor do atributo da entidade (EAV)
É considerado um anti-padrão por muitos, inclusive eu.
Aqui estão suas alternativas:
usar herança de tabela de banco de dados
use dados XML e funções SQLXML
use um banco de dados nosql, como o HBase
fonte
No PostgreSQL, uma maneira muito boa de lidar com estruturas EAV é o módulo adicional
hstore
, disponível para a versão 8.4 ou posterior. Cito o manual:Desde o Postgres 9.2, há também o
json
tipo e uma série de funcionalidades para acompanhá-lo (a maioria foi adicionada com a 9.3 ).O Postgres 9.4 adiciona o tipo de dados "JSON binário" (em grande parte superior!) À
jsonb
lista de opções. Com opções avançadas de índice.fonte
Se você possui um banco de dados que está usando a estrutura EAV, é possível consultar os dados de várias maneiras.
A resposta do @ Simon já mostra como executar uma consulta usando várias junções.
Dados de amostra usados:
Se você estiver usando um RDBMS com uma
PIVOT
função ( SQL Server 2005+ / Oracle 11g + ), poderá consultar os dados da seguinte maneira:Veja SQL Fiddle com demonstração
Se você não tiver acesso a uma
PIVOT
função, poderá usar uma função agregada com umaCASE
instrução para retornar os dados:Veja SQL Fiddle com demonstração
Ambas as consultas retornarão dados no resultado:
fonte
Engraçado ver como o modelo EAV db é criticado e até considerado como um "anti-padrão" por alguns.
Para mim, as principais desvantagens são:
No entanto, você definitivamente não deve descartar esta solução, e aqui está o porquê:
fonte