Bancos de dados sem mistério

O esquema do «Kotomarket»

11 min
O que você vai aprender
  • encontrar a tabela certa entre as cinco do «Kotomarket»: users, products, orders, order_items, events
  • ler um diagrama ER: determinar a cardinalidade de uma conexão (1:N, N:M, 1:1) pela posição da chave estrangeira
  • decompor uma conexão «muitos para muitos» usando uma tabela intermediária com duas FK — como order_items com order_id + product_id
  • explicar por que o conteúdo de um pedido não deve ser guardado como uma string de ids dentro de orders

Hoje QUERY traz para a mesa principal o índice inteiro de uma só vez. Cinco planos luminosos pairam no ar, girando devagar — um mapa do mundo que sobreviveu. Ao lado, cintila o registro de conservação anexado ao instantâneo, com uma linha sublinhada: «Entrego cinco tabelas e o rastro de uma sexta. — K.» Você conta os planos. Exatamente cinco. Onde está o rastro?

QUERY: Não se distraia com rastros. Primeiro aprenda estas cinco bem o bastante para encontrar o caminho de olhos fechados — o resto o arquivo mostra quando te julgar pronto.

As cinco tabelas do «Kotomarket»

Daqui em diante, vamos trabalhar com este banco — um instantâneo de uma loja virtual de 2024. Use-o como um mapa da loja: quem entrou, o que estava na vitrine, o que foi comprado e quais ações aconteceram antes da compra.

TabelaO que guarda
userscompradores: id, nome, cidade e data de cadastro
productsitens da vitrine: id, nome, categoria, preço e estoque
orderspedidos: id, user_id, data, status e total
order_itemsconteúdo dos pedidos: qual produto, quantas unidades e a que preço
eventseventos comportamentais: visualizações, adições ao carrinho e compras

As conexões são lidas assim: um user → muitos orders; um order → muitos order_items; um product → muitos order_items. Se você se perder, abra o esquema à direita — ele é como a planta do salão de vendas.

Vamos espiar a tabela de pedidos: em cada linha há um user_id — uma referência ao comprador. É assim que uma tabela se conecta a outra, e o mapa deixa de ser cinco ilhas separadas.

Cinco tabelas-planos holográficas giram como uma constelação, unidas por fios; à parte, quase imperceptível, aparece o contorno pontilhado de uma sexta
O mapa do arquivo: cinco tabelas e suas conexões. O registro de conservação promete também «o rastro de uma sexta» — mas, por enquanto, ele não aparece.

Kotomarket’s five tables

From here on we’ll be working with this database — a of an online shop from 2024. Hold it like a map of the store: who walked in, what’s on the shelves, what they bought, and what they did before buying.

TableWhat it holds
usersbuyers: id, name, city, and signup date
productsstorefront items: id, name, category, price, and stock
ordersorders: id, user_id, date, status, and total
order_itemsorder contents: which product, how many, and at what price
eventsbehavioral events: views, add-to-carts, and purchases

The links read like this: one user → many orders; one order → many order_items; one product → many order_items. If you get lost, open the schema on the right — it’s like the floor plan of the shop.

Let’s peek into the orders table: every row has a user_id — a reference to a buyer. That’s how one table links to another, and the map stops being five separate islands.

Os pedidos e sua conexão com o comprador por meio de user_id:
Query result
iduser_idstatustotal_amount
118paid5980.00
210paid19750.00
326cancelled9560.00
426paid15530.00
58paid26710.00
637paid42110.00

Como ler um diagrama ER

O mapa que QUERY desdobrou é o que a indústria chama de diagrama ER (entity–relationship): os retângulos são tabelas, as linhas entre eles são conexões por chaves estrangeiras. O mais importante em uma linha é a cardinalidade: quantas linhas de um lado correspondem a quantas do outro.

  • 1:N, um para muitos — a conexão mais comum. Um comprador, muitos pedidos. A chave estrangeira sempre fica do lado dos «muitos»: o user_id é guardado em orders, e não o contrário. Esta é a regra de leitura: achou a FK, achou o lado N.
  • N:M, muitos para muitos — um pedido tem muitos produtos, e um produto aparece em muitos pedidos. Uma conexão assim não pode ser representada diretamente em um banco relacional: não há onde colocar a chave estrangeira. Ela é decomposta em uma tabela intermediária — no nosso caso, order_items. Cada linha dela carrega um par de referências, order_id + product_id, e transforma uma única conexão N:M em duas conexões 1:N. De quebra, a própria conexão ganha atributos — a quantidade de unidades e o preço no momento da compra.
  • 1:1, um para um — mais raro: campos pesados ou privados, por exemplo, são movidos para uma tabela separada com a mesma chave.
-- A resolução N:M em ação: pares «pedido — produto» de order_items
SELECT order_id, product_id, quantity
FROM order_items
LIMIT 6;
usersidnameproductsidpriceordersiduser_ideventsuser_idproduct_idorder_itemsorder_idproduct_iduser_id → idproduct_id → idPKFK (reference)
Diagrama ER do «Kotomarket»: conexões 1:N de users para orders e a resolução N:M entre orders e products por meio de order_items.

Pegadinha: guardar o conteúdo de um pedido direto em orders — como uma string '7,12,3' ou um array de identificadores. Não dá para proteger esses dados com uma chave estrangeira, contá-los de forma confiável nem juntá-los com a vitrine sem acrobacias. Viu uma conexão «muitos para muitos» — crie uma tabela intermediária com duas chaves estrangeiras, como order_items.

Interview question

Pergunta de entrevista: como implementar uma conexão «muitos para muitos» em um banco relacional?

Resposta forte: por meio de uma tabela intermediária com duas chaves estrangeiras para as tabelas conectadas — como order_items com order_id e product_id: ela transforma N:M em duas conexões 1:N. De quebra, guarda atributos da própria conexão — quantidade, preço no momento da compra. A chave primária dessa tabela pode ser composta pelas duas FK ou ser um id substituto.

Check yourself
Em que ponto do esquema dá para ver qual produto entrou em qual pedido?