Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Базы Данных > Организация структуры таблиц БД, скидка на товары


Автор: Гриша 22.9.2006, 09:43
Здравствуйте.

Для интернет-магазина, мне необходимо разработать структуру таблиц, содержащих информацию о скидках на товары, 
для последующего расчета цены товара с учетом скидки.
:: Цена товара завист от различных опций, цвет, размер и т. д., поэтому один товар может иметь несколько цен.

Теоритические, пока что представляется так:
1) Скидка может быть установлена например только для партнера (partner_id), 
т.е. она будет действительна для всех категорий и товаров данного партнера.
2) Скидка может быть установлена например для партнера и категории товаров (partner_id, category_id),
т.е. она будет действительная для всех товаров данного партнера и категории.
3) Скидка может быть установлена для партнера, категории товара и выбранных товаров (artner_id, category_id, product_id),
т.е. она будет действительная для всех выбранных товаров данного партнера и категории.

Код

PRODUCTS
product_id | category_id | partner_id | product_name 
    1            1             1           Книга

PRICES
price_id | product_id | price
    1          1        1000.00
    2          1        1200.00


Практических идей никаких даже не получается, начинаю пытаться сделать на бумаге,
и просто незнаю даже с чего начать, ничего невыходит.

Автор: Igor_CH 22.9.2006, 10:30
Может так:

Таблица скидка

partner_id  |  category_id   |  product_id   |   скидка 
                                                                       -10
                                                                       -100
                                                                       -10%  (если отнимать в прцентах)

Автор: Гриша 22.9.2006, 10:56
Igor_CH, спасибо за ответ.

Я также начал когда писать таблицу, потом смотрю и никак, непойму как правильно объеденить такую таблицу с таблицой товаров (PRODUCTS), и как сделать так, что если я указал, только partner_id, то category_id и product_id должен быть любые, что у меня в итоге получается при объеденение, помойму ничего хорошего.
Так меня в ступор вогнал поиск решения это задачи.

Автор: Vaulter 22.9.2006, 15:38
Гриша, делай так
если ячейка в таблице скидок 
NULL - то любые.

то есть.
partner_id  |  category_id   |  product_id   |   скидка 
1 | NULL | NULL - скидка для всего партнеру
1 | 1 | NULL - скидка для всей категории этому партнеру
NULL | NULL | 1 - скидка на товар

Автор: Гриша 23.9.2006, 09:52
Vaulter, спасибо за ответ.

Но каую бы структуру я непридумывал, объеденить ее с таблицей товаров и извлеч нужную скидку никак неполучается.

Вот к примеру есть такой запрос на извлечение товаров:
Код

SELECT 
    * # Перечесляю нужные поля 
FROM 
    products 
    LEFT JOIN categories on products.category_id = categories.category_id     
    LEFT JOIN prices on products.product_id = prices.product_id             
    LEFT JOIN photos on products.product_id = photos.product_id 
    # Объеденение левостороннее, потому что фотографий для товара может не быть                     
WHERE 
    # Условия, сортировка 


// Собираю массив с данными товаров 
for ($count=0; $row = mysql_fetch_assoc($result); $count++) 
{         
    $result_array[$row['product_id']] = $row; 
}


А вот как же составить запрос, чтобы извлеч и скидку?

Автор: Vaulter 23.9.2006, 10:30
SELECT 
    * # Перечесляю нужные поля 
FROM 
    products 
    LEFT JOIN categories on products.category_id = categories.category_id     
    LEFT JOIN prices on products.product_id = prices.product_id             
    LEFT JOIN photos on products.product_id = photos.product_id 
    LEFT JOIN discount on discount.category_id = products.category_id OR discount.product_id = products.product_id

    # Объеденение левостороннее, потому что фотографий для товара может не быть                     
WHERE 
    # Условия, сортировка 

смотря какая логика.

Автор: Гриша 23.9.2006, 12:36
Vaulter, спасибо большое за ответ.

Я совсем забыл про то что при объеденение LEFT JOIN я могу, укзывать OR, AND.
Таблицы со скидками делаю так:
D
Код

ISCOUNTS (discount_id, discount) 
DISCOUNT_CATEGORY (discount_id, partner_id) 
DISCOUNT_CATEGORY (discount_id, category_id) 
DISCOUNT_PRODUCT (discount_id, product_id)


Соответвенно общий заппрос получается такой:
Код

SELECT 
    * # Перечесляю нужные поля 
FROM 
    products 
    LEFT JOIN categories on products.category_id = categories.category_id     
    LEFT JOIN prices on products.product_id = prices.product_id             
    LEFT JOIN photos on products.product_id = photos.product_id 

    LEFT JOIN discount_product on products.product_id = discount_product.product_id 
    LEFT JOIN discount_category on products.category_id = discount_category.category_id
    LEFT JOIN discount_partner on discount_partner.partner_id = discount_partner.partner_id
    LEFT JOIN discounts on discount_product.discount_id = discounts.discount_id OR 
    discount_category.discount_id = discounts.discount_id OR 
    discount_partner.discount_id = discounts.discount_id    
    # Объеденение левостороннее, потому что фотографий для товара может не быть                     
WHERE 
    # Условия, сортировка 


// Собираю массив с данными товаров 
for ($count=0; $row = mysql_fetch_assoc($result); $count++) 
{
     // Проверяю есть ли скидка  
     if(!empty($row['discount_partner']) && $row['discount_partner'] == $row['partner_id'])
            $row['price_new'] = $row['price'] - $row['price'] * $row['discount'] / 100;
    elseif(!empty($row['discount_category']) && $row['discount_category'] == $row['category_id'])
            $row['price_new'] = $row['price'] - $row['price'] * $row['discount'] / 100;
    elseif(!empty($row['discount_product']) && $row['discount_product'] == $row['product_id'])
            $row['price_new'] = $row['price'] - $row['price'] * $row['discount'] / 100;

    $row['price_new'] = (!empty($row['price_new'])) ? number_format($row['price_new'], 2) : '';   
    
    $result_array[$row['product_id']] = $row; 
}


В итоге получается, что если есть скидка на партнера (имеет больший приоритет в моем случае), значит остальные не проверяем, и т.д.
Быстренько проверил, пока все работает.
Спасибо вам большое за помощь.

Возможно вы мне сможете подсказать, насколько запрос такого рода может быть тяжелым для БД, опыта я не имею вобщем-то, поэтому незнаю запросы такого рода, с большим количество LEF JOIN, загружают БД?

Автор: Vaulter 23.9.2006, 12:48
Гриша, 
Цитата

Возможно вы мне сможете подсказать, насколько запрос такого рода может быть тяжелым для БД, опыта я не имею вобщем-то, поэтому незнаю запросы такого рода, с большим количество LEF JOIN, загружают БД?


меньше чем какие либо другие варианты. smile

Автор: Garret 23.9.2006, 13:41
Загружает конкретно(4 джойна 0_О).

Автор: Гриша 23.9.2006, 15:13
Спасибо всем за ответы.

Garret, немогли бы вы пояснить 4 джойна 0_О.

Я например когда просматриваю разные сайты, мне думается что у них нет всяких сложных запросов, что они как-то все просто оптимизируют. Мне несчем сравнить, и поэтому я весь в сомнениях.
Хотя бывает читаю, что где-то и по 100 запросов на странице бывает (но так же уточняется что они простые).

Но случай со скидками ведь я предполагаю, что во многих случаях варианты схожи с моим, занчит это нормально?

Автор: Garret 24.9.2006, 09:26
Гриша, имел ввиду что 4 джойна это многовато, запрос будет тормозной. Я стараюсь использовать максимум 2 джойна.

Автор: Vaulter 24.9.2006, 20:30
Garret, 
а если надо? smile

Автор: Гриша 25.9.2006, 07:01
Спасибо за ответы.

И запрос такой нужен, и чтобы небольшая нагрузка была )

Попробю поэксперементировать с кэшированием.

Автор: Гриша 4.10.2006, 18:49
Решил разделить описанный выше запрос на несколько меньших:
1) Один извлекает данные товаров
2) Второй извлекает ИД фотографий для товаров
3) Третий извлекает цену и скидку, для товаров

Третий запрос использует следующие таблицы:
Код

PRODUCTS (product_id, category_id, partner_id, product_name)
PRICES (price_id, product_id, price)

DISCOUNTS (discount_id, discount) 
DISCOUNT_CATEGORY (discount_id, partner_id) 
DISCOUNT_CATEGORY (discount_id, category_id) 
DISCOUNT_PRODUCT (discount_id, product_id


SQL запроса:
Код

SELECT    
    *    #Список столбцов
FROM 
    products
    LEFT JOIN prices ON products.product_id = prices.product_id            
    LEFT JOIN discount_product on products.product_id = discount_product.product_id 
    LEFT JOIN discount_category on products.category_id = discount_category.category_id
    LEFT JOIN discount_partner on products.partner_id = discount_partner.partner_id
    LEFT JOIN discounts on discount_product.discount_id = discounts.discount_id OR 
    discount_category.discount_id = discounts.discount_id OR 
    discount_partner.discount_id = discounts.discount_id            
WHERE
    products.product_id IN(0,5,7,8,9,10,15,13) AND
    price_default = 1 


EXPLAIN:
Код

id | select_type | table             | type | possible_keys | key         | key_len | ref         | rows | Extra  
1  | SIMPLE      | products          | ALL  | PRIMARY       | NULL        | NULL    | NULL        | 9    | Using where 
1  | SIMPLE      | discount_product  | ref  | product_id    | product_id  | 4       | product_id  | 1    |
1  | SIMPLE      | discount_category | ref  | category_id   | category_id | 4       | category_id | 1    |
1  | SIMPLE      | discount_partner  | ref  | partner_id    | partner_id  | 4       | partner_id  | 1    |
1  | SIMPLE      | prices            | ref  | product_id    | product_id  | 4       | product_id  | 1    | Using where 
1  | SIMPLE      | discounts         | ALL  | PRIMARY       | NULL        | NULL    | NULL        | 3    |   


При описании запроса видно, что таблица Products и таблица discounts просматриваются полностью.
Я полагал, что таблица discounts будет использовать индексы и полностью не будет просмтариваться.
В результате получается, что если в таблице products будет 1000 строк, а в таблице discounts будет 10 строк, то всего MySQL потребуется просмотреть 10*1000=10000 строк и т.д.

Прошу совета по оптимизации/составлению запроса.

Автор: skyboy 4.10.2006, 19:00
зачем делаешь  "products.product_id IN(0,5,7,8,9,10,15,13)"? почему не равенство?

Автор: Гриша 4.10.2006, 19:43
skyboy, спасибо за ответ.
Ради интереса попробовал сделать "products.product_id = 5 or products.product_id = 7" и т.д., результат один и тот же.
А IN() я использую потому, что так удобнее. Хочу вывести на странице 5 товаров, извлекаю 5 ИД, передаю их в данный запрос в функцию IN(), хочу 10 передаю 10, проще чем у меня в запросе будет 10 условий (при помощи цикал), выполняется быстрее.
На оптимизации данного запроса это не повлияет.

Автор: Гриша 4.10.2006, 21:45
http://hosting.skif.net/docs/mysql/manual.ru_toc.html#Where_optimisations

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)