Есть таблица "Клиенты". Структура типа: id, имя, адрес и т.д. Есть товары (около 50): Товар1, Товар2, Товар3 и т.д. Нужно иметь вывод, например, - Все клиенты, которые покупают Товар1. Как лучше сформировать структуру, чтобы она максимально соответствовала нормализации? В форме при вводе/редактировании данных клиента нужно отмечать чекбоксами те позиции, по которым работает клиент. Я не так давно работаю с БД, не могу точно для себя представить такое отношение. Первое, что приходит в голову - это конечно же не пихать в таблицу клиенты все поля с товарами =) Мой ход мысли: 1. Создаю таблицу products [sql] CREATE TABLE products (product_id SMALLINT UNSIGNED, pname VARCHAR(20), CONSTRAINT pk_products PRIMARY KEY (product_id) );[/sql] 2. Теперь при выводе формы делаю циклом чекбоксы по каждому товару из таблицы product. Т.о. у меня появляется форма с помощью которой я могу связать id клиента и id товаров. 3. Т.е. мне необходимо установить отношение одного к множеству (одного клиента к множеству товаров). 4. Так как я ламос, устанавливаю прогу MySQL Workbench. И буду с ее помощью строить БД. Фу-у-х ) Пишу по ходу... сорри... Она мне показывает что отношение у меня не "один к многим", а "множество к множеству", вроде бы как... если что поправьте. И отсюда получаю, что мне нужна связующая таблица, Бенч дает такой запрос, но ессно я его переделаю... Т.е. таблица с двумя столбцами: id_продукта и id_клиента. [sql]CREATE TABLE IF NOT EXISTS `mydb`.`clients_has_product` ( `clients_id_clients` INT NOT NULL , `product_id_product` INT NOT NULL , PRIMARY KEY (`clients_id_clients`, `product_id_product`) , INDEX `fk_clients_has_product_product1` (`product_id_product` ASC) , INDEX `fk_clients_has_product_clients` (`clients_id_clients` ASC) , CONSTRAINT `fk_clients_has_product_clients` FOREIGN KEY (`clients_id_clients` ) REFERENCES `mydb`.`clients` (`id_clients` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_clients_has_product_product1` FOREIGN KEY (`product_id_product` ) REFERENCES `mydb`.`product` (`id_product` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = MyISAM DEFAULT CHARACTER SET = cp1251[/sql] Теперь вопрос: Т.е. для такой связи мне нужна еще одна таблица получается? И после ввода данных из формы - я прохожусь циклом по переменным с товаром и если чекбокс есть, то в ту связующую таблицу ввожу id клиента и товары, которые к нему относятся? Это будет правильно? А вывод, который мне нужен - Клиенты по Товару1 будет строиться, что-то типа: [sql]SELECT clients.name_client FROM clients INNER JOIN [связующая таблица] ON (id_продукта = Товар1);[/sql] Скажите это будет правильно? Когда садился писать вопрос - не думал что столько напишу... просто был в процессе, по времени заняло час.
многабукафф, ниасилил С клиентами и продуктами всё понятно - это отдельные сущности. Вам нужна связь многие ко многим. У одного клиента может быть множество продуктов. Одним продуктом могут пользоваться множество клиентов. Создаем таблицу связей clients_has_product с двумя полями client_id, product_id, по каждому полю не забудьте обычный индекс. Запросы Известен клиент, надо выбрать все продукты SELECT clients.name_client, products.pname FROM clients INNER JOIN clients_has_product ON clients.id = clients_has_product.client_id LEFT JOIN products ON products.id = clients_has_product.product_id WHERE clients.id = тут наш клиент Известен продукт выбрать всех клиентов SELECT clients.name_client, products.pname FROM products INNER JOIN clients_has_product ON products.id = clients_has_product.product_id LEFT JOIN clients ON clients.id = clients_has_product.client_id WHERE products.id = тут наш продукт Вроде должно работать)) не проверял, писал минут 5 )))) Думаю идея вам понятна В любом случае - советую сначала создать базу, заполнить тестовыми данными и поиграться с запросами. Разобраться как их строить, посмотреть какие данные приходят php-интерфейс и формы - дело десятое. Бизнес-логика на первом месте
Спасибо за быстрый ответ и содержательный ответ =) То, что множество ко множеству я тоже пришел в п.4 моей повести. И то что это правильно - немного этому рад. А вот насчет: Вот тут сложности... Бенчем то тоже выдало что нужно вводить индексы: [sql] INDEX `fk_clients_has_product_product1` (`product_id_product` ASC) , INDEX `fk_clients_has_product_clients` (`clients_id_clients` ASC) , CONSTRAINT `fk_clients_has_product_clients` FOREIGN KEY (`clients_id_clients` ) REFERENCES `mydb`.`clients` (`id_clients` ) ON UPDATE NO ACTION, CONSTRAINT `fk_clients_has_product_product1` FOREIGN KEY (`product_id_product` ) REFERENCES `mydb`.`product` (`id_product` ) ON DELETE NO ACTION ON UPDATE NO ACTION) [/sql] Но вот как это на деле применяется - пока вообще понять не могу... Беру книги и буду учить теорию. Насчет советов по бизнес-логике и экспериментами с базой - понял, спасибо, буду работать в этом направлении.
с Workbench не работал никогда, но показалось вот что - он Вас не путает такими громоздкими записями? Может в обычном phpma попробовать? он содержит весь необходимый функционал, разве что без визуальщины
Громоздкие записи - пугают, но кое в чем он мне помог. Я сейчас эксперементирую просто. Дело в том что в нем можно проектировать визуально БД и наглядно видно где-какие связи. Понятно, что со временем понимание прийдет и это уже вряд ли будет актуально. В phpMyAdmin работаю все время и еще пробую с NaviCat.
Задание выполнил в полном объеме. tommyangelo, еще раз спасибо! В ходе выполнения возникли следующие вопросы: 1. Устранить дублирование данных в таблице при заполнении и редактировании. 2. Отображать CHECKED в чек-боксах товара, который уже введен в БД и относится к данному клиенту. 3. Удалять товары по клиенту, CHECKED которых аннулирован. Вроде все решил и все работает! ) Конечно, для нормального программера - это легкий вопрос, но я, для своего уровня - скилл качнул нормально.