Bonjour à tous,
Tout d'abord, je tiens à m'excuser, si la question vous paraîtrait néophyte, mais je me suis pas mal documenté pendant une grosse semaine avant de me lancer dans la conception, mais j'en ai assez de faire défaire, supprimer, etc...
Enfin en soit un SGBD ce n'est pas compliqué à maîtriser, mais la modélisation optimale des tables, je trouve ça vraiment casse-tête.
Les seules BDD que j'avais faites jusqu'à présent étaient sous NOTION, et avec un tableur, mais ici, c'est totalement différent, et la logique ne me tombe pas encore, du a ses anciennes façons de faire.

Je vous donne ici mon schéma que je voyais pour faire cette base
(https://ibb.co/7GtpZDr)

La ou je bloque un peu c'est que par exemple, Recette dois contenir forcément plusieurs ingrédients, donc vu que le FK est de type SMINT(6), comment je défini plusieurs ingrédients pour une recette ?
Même chose pour fiche, car une fiche dois contenir un ensemble de recette qui forme une fiche technique
Merci de m'avoir lu

6 réponses


Hello :)

Alors ta relation entre recettes et ingrédients tu l'as fait à l'envers, du coup t'es bloqué x)

Il faut que tu inverses, vires recette_ingredients de la table recettes et ajoutes recette_id dans la table ingredients

Comme ça quand tu récupères la table recette, tu aura juste à récupérer tous les ingrédients qui ont le même recette_id que l'id que la recette

select * from recettes r join ingredients i on i.recette_id = r.id

Et voilou :)

Maintenant si un ingrédient peut être liéé à plusieurs recettes alors c'est une autre mécanique, il faut faire une table pivot entre recettes et ingrédients

linuxpit
Auteur

Merci pour ta réponse.
Alors je suis désolé mais je ne comprend pas l'inversion que tu explique, car je croyais que c'étais bidirectionnel.

Pour la requête, je n'ai pas encore créer de contenu dans mes bases car je tombe pas d'accord sur mes tables, si je devais te dire combien de fois j'ai changer mon fichier .sql :-)

Alors oui en effet les ingrédients seront utilisé par plusieurs recettes , et les fiches utiliseront plusieurs recette
Je te file au cas ou mon fichier sql
PS: Je n'ai pas encore créer les clef étrangère, j'attend d'abord de voir si je peux arriver a ce que je veux faire avec cette configuration.

-- Création de la base de donnée (trouvetarecette)

CREATE DATABASE IF NOT EXISTS `trouvetarecette`;
USE `trouvetarecette`;

-- Suppression des tables

DROP TABLE IF EXISTS `fiches`;
DROP TABLE IF EXISTS `recettes`;
DROP TABLE IF EXISTS `ingredients`;
DROP TABLE IF EXISTS `categorie`;

-- Création de la table Catégorie

CREATE TABLE IF NOT EXISTS `categorie` (
    categorie_id SMALLINT(6) PRIMARY KEY AUTO_INCREMENT NOT NULL,
    categorie_nom ENUM('Crèmes de base','Pâtes de base','Glaçages','Biscuits','Entremets','Gâteaux','Cakes','Mousses','Glaces et Sorbets','Compotés','Inserts','Tartes','Pâte à tartiner','Meringues','Mignardises','Macarons','Décorations') NOT NULL
)
ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Création de la table ingrédient

CREATE TABLE IF NOT EXISTS `ingredients` (
    ingredients_id SMALLINT(6) PRIMARY KEY AUTO_INCREMENT NOT NULL,
    ingredients_nom VARCHAR(50) NOT NULL UNIQUE,
    ingredients_marque VARCHAR(50) UNIQUE
) 
ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Création de la table principale recettes

CREATE TABLE IF NOT EXISTS `recettes` (
    recettes_id SMALLINT(6) PRIMARY KEY AUTO_INCREMENT NOT NULL,
    recettes_nom VARCHAR(100) NOT NULL UNIQUE,
    recettes_categorie SMALLINT(6) NOT NULL,
    recettes_ingredients SMALLINT(6) NOT NULL,
    recettes_frequence VARCHAR(50),
    recettes_duree SMALLINT(6) NOT NULL DEFAULT 0,
    recettes_date DATE,
    recettes_approuve BOOLEAN,
    recettes_etapes TEXT NOT NULL
)
ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Création de la table Fiches (pour les fiches technique complètes)

CREATE TABLE IF NOT EXISTS `fiches` (
    fiches_id SMALLINT(6) PRIMARY KEY AUTO_INCREMENT NOT NULL,
    fiches_nom VARCHAR(100) NOT NULL,
    fiches_saison ENUM('Printemps','ETE','Automne','Hiver') NOT NULL,
    fiches_approuve BOOLEAN
)
ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Bien le bonjour.

Alors, pour ton problème, c'est surtout qu'il te faut une table entre tes ingrédients et tes recettes (Une recette a plusieurs ingrédients et un ingrédient a plusieurs recettes), c'est une relation n-n, ou plus communément appelée ManyToMany.

La table au milieu contiendra les informations qui peuvent lier les deux tables, ainsi que les informations que tu ne peux pas stocker entre les deux (quantité des ingrédients, etc)

Petit exemple :

# Ingrédients
- ingredients_id
- ingredients_nom
- ingredients_marque
- ....

# Recettes
- recettes_id
- recettes_nom
- recettes_categorie
- recettes_duree
- recettes_date
- recettes_approuvee
- recettes_etapes
- ...

# Ingredients_Recettes
- ingredients_id
- recettes_id
- quantite
- ...

Ensuite, quand tu récupère ta recette, tu passes par la table au milieu pour récupérer la liste de tes ingrédients.

--- Fait attention avec le *, tu veux récupérer des données qui ne te sont pas forcément nécessaire.
SELECT * FROM Recettes AS r
INNER JOIN Ingredients_Recettes AS ir ON ir.recettes_id = r.recettes_id
INNER JOIN Ingredients AS i ON i.ingredients_id = ir.ingredients_id
WHERE r.recettes_id = :recette_id;

Pour ajouter un ingrédient à ta recette, rien de plus simple, tu le fais directement dans la table Ingredients_Recettes

INSERT INTO Ingredients_Recettes (ingredients_id, recettes_id, quantite)
VALUES (:ingredients_id, :recettes_id, :quantite);

Et tu peux faire parail pour tes fiches dans le cas où tu peux avoir plusieurs recettes dans une ficher et plusieurs fiches pour une recette.

Alors quand je parle d'inversion ça veuut dire que ta clé étrangère (recettes_ingredients SMALLINT(6) NOT NULL) au lieux de la mettre dans la table recette pour identifier un ingrédient tu la met dans ingredients pour identifier une recette, une clé étrangère ne peut identifier qu'un seul élément ^^'

Ah alors faut une table pivot, du coup regardes la réponse de Kareylo :p

linuxpit
Auteur

Re bonsoir à vous deux
Bon j'ai un peu chercher de mon coté et je suis arriver à quelque chose qui ma foi, me plait dans le résultat, je ferai la même chose pour la table fiche technique, mais ca, ce sera après, avant toute chose il me faudra mes recettes .
Je vous donne ici les requetes SQL de creation des tables, et je vous met également MLD SEMI-FINAL

MLD SEMI-FINAL => https://ibb.co/mt7zCY7
Mes requetes SQL => https://www.mycompiler.io/view/EategNDD56j

@popotte , oui j'ai compris maintenant ce que tu voulais dire, je t'avoue que je commence à mieux comprendre maintenant, a force de manger de la lecture.

@Kareylo
Merci pour tes conseils, je suis parti sur ton idée sans vraiment savoir si j'étais dans le bon mais après de nombreux test cela semble fonctionne

SELECT r.recettes_nom AS 'La recette complete',c.categorie_nom AS CAT,i.ingredients_nom AS INGR,bi.bind_quantite,bi.bind_unite 
FROM recettes r 
JOIN bind_ir bi ON bi.bind_recettes_id = r.recettes_id
JOIN ingredients i ON bi.bind_ingredients_id = i.ingredients_id
JOIN categorie c ON r.recettes_categorie = c.categorie_id
WHERE recettes_nom = 'Javanais';

=> https://ibb.co/9Tj5D2F <= résultat qui correspond à ce que je voulais

Par contre, je me questionne, cela veut dire si je comprend bien qu'il y aura autant d'entrées javanais que d'ingrédients qui le compose ?
Un peu comme ici => https://ibb.co/9Tj5D2F
on peut jouer avec les filtres biensur mais je m'étonne de ce mode de fonctionnement ou alors c'est moi qui m'y prend mal.

Autre question qui me tarode, bon ici j'ai mis quelque entrée bidon pour les tests , mais comment est-ce qu'on fait quand on a des milliers d'ingrédients
ici j'ai tout a porter de vue => https://ibb.co/PQrKNVX
Mais avec des milliers d'entrées ce sera pas le cas, comment vous faites pour les correspondance id ? me dites pas qu'on vérifie à chaque fois la correspondance en allant dans la table.

Merci les gars

Top :p

Alors Pour ta question sur les milliers d'entrées, il faut que tu fasses une requete globale, et ensuite tu filtre le résultat, comme ça tu n'a pas besoin de faire plein d'appel vers la base de données

Tu prépares cette requuête

SELECT r.recettes_nom AS 'La recette complete',c.categorie_nom AS CAT,i.ingredients_nom AS INGR,bi.bind_quantite,bi.bind_unite 
FROM recettes r 
JOIN bind_ir bi ON bi.bind_recettes_id = r.recettes_id
JOIN ingredients i ON bi.bind_ingredients_id = i.ingredients_id
JOIN categorie c ON r.recettes_categorie = c.categorie_id

(Bref j'ai repris ce que tu as fait mais en virant le where x) )

Et tu fais un fetchAll() pour avoir la liste complète que tu fou dans une variable $recettes = $query->fetchAll();

Et ensuite tu peux faire tes filtre depuis $recettes pour choper depuis recette_nom, pas besoin de faire plein de requêtes de correspondances, tu as déjà une liste complète de toutes les recettes avec les ingrédients qui correspondent :p

Et pas de problème de mémoire PHP, j'ai des projets où je dois gérer des dizaines de millions d'entrées, et ça arrive à supporter (bon dans mon cas je dois optimiser, mais dans ton cas tu peux faire ta requete direct ça passera ;))