Esquema proposto
Primeiro e acima de tudo, aqui está um exemplo do meu esquema proposto para referência em toda a minha postagem:
Clothes
----------
ClothesID (PK) INT NOT NULL
Name VARCHAR(50) NOT NULL
Color VARCHAR(50) NOT NULL
Price DECIMAL(5,2) NOT NULL
BrandID INT NOT NULL
...
Brand_1
--------
ClothesID (FK/PK) int NOT NULL
ViewingUrl VARCHAR(50) NOT NULL
SomeOtherBrand1SpecificAttr VARCHAR(50) NOT NULL
Brand_2
--------
ClothesID (FK/PK) int NOT NULL
PhotoUrl VARCHAR(50) NOT NULL
SomeOtherBrand2SpecificAttr VARCHAR(50) NOT NULL
Brand_X
--------
ClothesID (FK/PK) int NOT NULL
SomeOtherBrandXSpecificAttr VARCHAR(50) NOT NULL
Declaração do problema
Eu tenho uma mesa de roupas com colunas como nome, cor, preço, marca e assim por diante para descrever os atributos de uma determinada peça de roupa.
Aqui está o meu problema: marcas diferentes de roupas exigem informações diferentes. Qual é a melhor prática para lidar com um problema como esse?
Observe que, para meus propósitos, é necessário encontrar informações específicas da marca a partir de uma entrada de roupas . Isso ocorre porque eu exibo primeiro as informações de uma entrada de roupas para o usuário, após o qual devo usar as informações específicas da marca para comprar o item. Em resumo, deve haver uma relação direcional entre roupas (de) e as tabelas brand_x .
Solução proposta / atual
Para lidar com isso, pensei no seguinte esquema de design:
A tabela de roupas terá uma coluna de marca que pode ter valores de ID que variam de 1 a x, onde um ID específico corresponde a uma tabela específica de marca. Por exemplo, o valor do ID 1 corresponderá à tabela brand_1 (que pode ter uma coluna de URL ), o id 2 corresponderá à marca_2 (que pode ter uma coluna de fornecedor ) etc.
Assim, para associar uma entrada de roupas específica a suas informações específicas da marca, imagino que a lógica no nível do aplicativo seja algo parecido com isto:
clothesId = <some value>
brand = query("SELECT brand FROM clothes WHERE id = clothesId")
if (brand == 1) {
// get brand_1 attributes for given clothesId
} else if (brand == 2) {
// get brand_2 attributes for given clothesId
} ... etc.
Outros comentários e pensamentos
Estou tentando normalizar meu banco de dados inteiro no BCNF e, embora tenha sido o que eu criei, o código do aplicativo resultante me deixa muito ansioso. Não há como impor relações, exceto no nível do aplicativo, e, portanto, o design parece muito invasivo e, antecipadamente, muito suscetível a erros.
Pesquisa
Fiz questão de examinar as entradas anteriores antes de fazer uma postagem. Aqui está um post com um problema quase idêntico que eu consegui encontrar. Fiz este post de qualquer maneira, porque parece que a única resposta fornecida não tem uma solução baseada em design ou SQL (isto é, menciona OOP, herança e interfaces).
Também sou um novato no que diz respeito ao design de banco de dados e, por isso, gostaria de receber informações.
Parece que há respostas mais úteis no Stack Overflow:
- Aqui
- E aqui
- Aqui e aqui (conceito-chave: herança da tabela de classes)
Mencionei as soluções lá e sugiro que outras pessoas também encontrem minha pergunta.
Apesar dos links fornecidos acima, ainda estou à procura de respostas aqui e agradeceria qualquer solução fornecida!
Estou usando o PostgreSQL.
fonte
O que você está descrevendo é, pelo menos em parte, um catálogo de produtos. Você tem vários atributos comuns a todos os produtos. Eles pertencem a uma tabela bem normalizada.
Além disso, você tem uma série de atributos específicos da marca (e eu espero que possam ser específicos do produto). O que seu sistema precisa fazer com esses atributos específicos? Você tem lógica de negócios que depende do esquema desses atributos ou apenas os lista em uma série de pares "label": "value"?
Outras respostas sugerem usar o que é essencialmente uma abordagem CSV (seja essa
JSON
ouARRAY
ou não) - estas abordagens, renunciar esquema relacional regulares manipulação movendo o esquema de metadados e para os dados em si.Existe um padrão de design portátil para isso, que se encaixa muito bem nos bancos de dados relacionais. É EAV (entidade-atributo-valor). Tenho certeza que você leu em muitos lugares que "EAV é o mal" (e é). No entanto, há um aplicativo específico em que os problemas com o EAV não são importantes e são os catálogos de atributos do produto.
Todos os argumentos usuais contra o EAV não se aplicam a um catálogo de recursos do produto, pois os valores dos recursos do produto geralmente são regurgitados apenas em uma lista ou, na pior das hipóteses, em uma tabela de comparação.
O uso de um
JSON
tipo de coluna exige que você imponha restrições de dados fora do banco de dados e o force à lógica do aplicativo. Além disso, o uso de uma tabela de atributos para cada marca tem as seguintes desvantagens:Não é especialmente difícil recuperar dados sobre um produto com recursos específicos da marca. É indiscutivelmente mais fácil criar um SQL dinâmico usando o modelo EAV do que seria usando o modelo de tabela por categoria. Na tabela por categoria, você precisa de reflexão (ou sua
JSON
) para descobrir quais são os nomes das colunas dos recursos. Em seguida, você pode criar uma lista de itens para uma cláusula where. No modelo EAV,WHERE X AND Y AND Z
torna - seINNER JOIN X INNER JOIN Y INNER JOIN Z
, portanto, a consulta é um pouco mais complicada, mas a lógica para criar a consulta ainda é totalmente orientada por tabela e será mais do que escalável o suficiente se você tiver os índices adequados criados.Existem várias razões para não usar o EAV como uma abordagem geral. Esses motivos não se aplicam a um catálogo de recursos do produto, portanto não há nada errado com o EAV neste aplicativo específico.
Certamente, esta é uma resposta curta para um tópico complexo e controverso. Eu já respondi perguntas semelhantes antes e entrei em mais detalhes sobre a aversão geral ao EAV. Por exemplo:
Eu diria que o EAV é usado com menos frequência ultimamente do que costumava ser, principalmente por boas razões. No entanto, acho que também não é bem compreendido.
fonte
Usando JSON e PostgreSQL
Eu acho que você está fazendo isso mais difícil do que precisa e você será mordido mais tarde. Você não precisa do modelo de entidade-atributo-valor, a menos que realmente precise do EAV.
Não há absolutamente nada de errado com esse esquema.
Agora você pode consultá-lo usando uma associação simples
E qualquer um dos operadores JSON trabalha em uma cláusula where.
Como uma observação lateral, não coloque os URLs no banco de dados. Eles mudam com o tempo. Simplesmente crie uma função que os aceite.
como queiras. Se você estiver usando o PostgreSQL, pode até usar hashids .
Também de nota especial,
jsonb
digno é armazenado como binário (portanto, o 'b') e também pode ser indexado, ou SARGable ou qualquer outra coisa que as crianças legais estejam chamando nos dias de hoje:CREATE INDEX ON brands USING gin ( attributes );
A diferença aqui está na simplicidade da consulta ..
Que tal um diferente ..
fonte
Uma solução fácil é incluir todos os atributos possíveis como colunas na tabela de roupas principal e tornar todas as colunas específicas da marca anuláveis. Essa solução interrompe a normalização do banco de dados, mas é muito fácil de implementar.
fonte