За последние 24 часа нас посетили 15610 программистов и 1547 роботов. Сейчас ищут 894 программиста ...

Вопрос по правильной организации данных в БД ()

Тема в разделе "PHP и базы данных", создана пользователем HAMANN, 13 янв 2011.

  1. HAMANN

    HAMANN Активный пользователь

    С нами с:
    25 июл 2009
    Сообщения:
    24
    Симпатии:
    0
    Есть таблица "Клиенты".

    Структура типа:
    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]

    Скажите это будет правильно?

    Когда садился писать вопрос - не думал что столько напишу... просто был в процессе, по времени заняло час.
     
  2. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    многабукафф, ниасилил

    С клиентами и продуктами всё понятно - это отдельные сущности.

    Вам нужна связь многие ко многим. У одного клиента может быть множество продуктов. Одним продуктом могут пользоваться множество клиентов.

    Создаем таблицу связей 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-интерфейс и формы - дело десятое. Бизнес-логика на первом месте
     
  3. HAMANN

    HAMANN Активный пользователь

    С нами с:
    25 июл 2009
    Сообщения:
    24
    Симпатии:
    0
    Спасибо за быстрый ответ и содержательный ответ =)

    То, что множество ко множеству я тоже пришел в п.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]

    Но вот как это на деле применяется - пока вообще понять не могу... Беру книги и буду учить теорию.

    Насчет советов по бизнес-логике и экспериментами с базой - понял, спасибо, буду работать в этом направлении.
     
  4. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    с Workbench не работал никогда, но показалось вот что - он Вас не путает такими громоздкими записями?
    Может в обычном phpma попробовать? он содержит весь необходимый функционал, разве что без визуальщины
     
  5. HAMANN

    HAMANN Активный пользователь

    С нами с:
    25 июл 2009
    Сообщения:
    24
    Симпатии:
    0
    Громоздкие записи - пугают, но кое в чем он мне помог.
    Я сейчас эксперементирую просто. Дело в том что в нем можно проектировать визуально БД и наглядно видно где-какие связи. Понятно, что со временем понимание прийдет и это уже вряд ли будет актуально.

    В phpMyAdmin работаю все время и еще пробую с NaviCat.
     
  6. Padaboo

    Padaboo Старожил
    Команда форума Модератор

    С нами с:
    26 окт 2009
    Сообщения:
    5.242
    Симпатии:
    1
    Эххх, завтра экзамен по бд ...
    шпоры, по вопросу нормализации к НФБК)))
     
  7. HAMANN

    HAMANN Активный пользователь

    С нами с:
    25 июл 2009
    Сообщения:
    24
    Симпатии:
    0
    Разобрался с теорией по индексам и начал работать над вопросом.

    tommyangelo, спасибо!
     
  8. HAMANN

    HAMANN Активный пользователь

    С нами с:
    25 июл 2009
    Сообщения:
    24
    Симпатии:
    0
    Задание выполнил в полном объеме. tommyangelo, еще раз спасибо!

    В ходе выполнения возникли следующие вопросы:
    1. Устранить дублирование данных в таблице при заполнении и редактировании.
    2. Отображать CHECKED в чек-боксах товара, который уже введен в БД и относится к данному клиенту.
    3. Удалять товары по клиенту, CHECKED которых аннулирован.

    Вроде все решил и все работает! )

    Конечно, для нормального программера - это легкий вопрос, но я, для своего уровня - скилл качнул нормально.
     
  9. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    HAMANN
    поздравляю с успехом :)