2013-06-07 5 views
2

Я хотел бы получить список всех продуктов со связанными с ними ценами за данный период.MySql найти товары и цены

Таблица продукта:

Id 
Name 
Description 

Цена Стол:

Id 
Product_id 
Name 
Amount 
Start 
End 
Duration 

Самое главное, чтобы не здесь, является то, что продукт может иметь mutliple цены, даже за тот же период, но не с той же продолжительностью. Например, цена от «2013-06-01 -> 2013-06-08», а другая от «2013-06-01 -> 2013-06-05»

Итак, моя цель - получить, для данный период, списки всех продуктов, с разбивкой на 10 продуктов, например, присоединились к ценам, существующим за этот период.

Основной способ сделать это будет:

SElECT * 
FROM product 
LEFT JOIN prices ON ... 
WHERE prices.start >= XXX And prices.end <= YYY 
LIMIT 0,10 

Проблема при использовании этого простого решения, является то, что я не могу получить только 10 продуктов, но 10 Продукты * Цены, которые не является приемлемым в мое дело.

Таким образом, решение будет:

SElECT * 
FROM product 
LEFT JOIN prices ON ... 
WHERE prices.start >= XXX And prices.end <= YYY 
GROUP BY product.id 
LIMIT 0,10 

Но проблема здесь, я буду только получать «1» цена каждого продукта.

Так что я задаюсь вопросом, каким будет лучший способ справиться с этим. Я мог бы например использовать групповую функцию, такую ​​как «group_concat», и получить в поле все цены в строке, например «200/300/100» и т. Д. Это кажется странным и потребует работы на стороне сервера, чтобы преобразовать в удобочитаемую информацию, но это может сработать.

Другим решением было бы использовать различные колонки для каждой цены, в зависимости от продолжительности:

SELECT 
    IF(NOT ISNULL(price.start) AND price.duration = 1, price.amount , NULL) AS price_1_day 
    ---- same here for all possible durations --- 
From ... 

Thta будет работать тоже, я думаю (я не совсем уверен, если это возможно, однако), но Мне может понадобиться создать около 250 столбцов, чтобы охватить все возможности. Это безопасный вариант?

Любая помощь будет оценена

+0

поскольку вы ограничены 10 продуктов у вас есть 2 варианта: использовать 'GROUP_CONCAT', как вы сказали, или имеют 2 запросов, по одному для продукта и один для цен и присоединиться данные на клиентской части. Второй вариант даст вам большую гибкость. – Stephan

+0

Если вы используете группу concat, помните, что ограничение по умолчанию - 1024 символа. Это не должно быть проблемой, если у вас много многих цен. При необходимости его можно изменить с помощью системной переменной group_concat_max_len. – rollcona

+0

Вы хотите, чтобы запись для 10 продуктов или не более 10 записей для каждого продукта, я немного запутался в вашем подходе. – Meherzad

ответ

0

Это трудно сказать, без выборки данных и желаемого выхода, но вы можете попробовать что-то вроде этого

SElECT p.*, q2.* 
    FROM 
(
    SElECT Product_id 
    FROM Price 
    WHERE `start` >= '2013-05-01' AND `end` <= '2013-05-15' 
    GROUP BY Product_id 
    LIMIT 0,10 
) q1 JOIN 
(
    SELECT * 
     FROM Price 
    WHERE `start` >= '2013-05-01' AND `end` <= '2013-05-15' 
) q2 ON q1.Product_id = q2.Product_id JOIN product p 
    ON q1.Product_id = p.Id 

Вот SQLFiddle демо

+0

Я тоже думал об этом решении, но разве это не слишком сложно получить те же элементы с двумя эквивалентными запросами? Будет ли MySql работать с этим хорошо, например, повторно использовать какой-то кеш? Мой последний запрос намного сложнее (много подключений и условий в разделе Price), и запуск дважды этого запроса может стоить мне сотни миллисекунд. – elwood

+0

Кстати, у меня также возникла идея «SELECT * FROM product WHERE id IN (SELECT id FROM product LEFT JOIN prices ..... ", но я действительно не уверен в предварительной подготовке, потому что запрос в части« WHERE IN », безусловно, попытается отсканировать все строки – elwood

+0

@elwood Это, безусловно, связано с большим количеством работы, но так же как и ваши требования, но, чтобы точно сказать, что их нужно тестировать на реальных данных. Если у вас есть все индексы для всех соединений и условий фильтрации IMHO, он должен работать нормально. – peterm

1

I считают, что group_concat будет лучшим способом продвижения по этому пути, поскольку его основная цель состоит в объединении нескольких частей данных, относящихся к определенному столбцу.

Однако, приспосабливаясь к скрипту SQL-скрипта, это можно сделать в 1 запросе, если использовать определенные пользователем переменные.(Если один игнорирует первоначальный запрос для установки ВАРА)

http://dev.mysql.com/doc/refman/5.7/en/user-variables.html

SET @productTemp := '', @increment := 0; 

SElECT 
    @increment := if(@productTemp != Product_id, @increment + 1, @increment) AS limiter, 
    @productTemp :=Product_id as Product_id, 
    Product.name, 
    Price.id as Price_id, 
    Price.start, 
    Price.end 
FROM 
    Product 
LEFT JOIN 
    Price ON Product.Id=Price.Product_id 
WHERE 
    `start` >= '2013-05-01' AND `end` <= '2013-05-15' 
GROUP BY 
Price_id 
HAVING 
    limiter <=2 

Что мы делаем здесь только приращение определенного пользователя вара «инкрементор» только тогда, когда идентификатор продукта не совпадают последний из которых был встречен.

Поскольку псевдонимы не могут использоваться в условии WHERE, мы должны GROUP по уникальному идентификатору (в данном случае ID цены), чтобы мы могли уменьшить результат, используя HAVING. В этом случае у меня есть полный набор результатов, который должен включать в себя 3 идентификатора продукта, уменьшенный до показа только 2.

Обратите внимание: это не решение, которое я бы рекомендовал в больших наборах данных или в производственной среде. Даже в руководстве mysql указывается, что пользовательские вары могут вести себя несколько неустойчиво в зависимости от того, какие пути использует оптимизатор. Тем не менее, я использовал их для большого эффекта для некоторых внутренних статистических данных в прошлом.

Fiddle: http://sqlfiddle.com/#!2/96c92/3

Смежные вопросы