2009-12-17 3 views
1

У меня есть информация о количестве в моей базе данных.
1 стол, «запас», содержит productid (sku) вместе с количеством и именем файла, откуда он пришел.Выберите самую новую запись из объединенной таблицы MySQL

Другая таблица, «файл запаса», содержит все обработанные имена файлов вместе с датами.

Теперь мне нужно получить все продукты с их последними значениями запаса.

Это дает мне все продукты, несколько раз со всей их количества штока (в результате 300.000 записей)

ВЫБОР stock.stockid, stock.sku, stock.quantity, stockfile.filename, stockfile.date
С учетом запаса
INNER JOIN stockfile ON stock.stockfileid = stockfile.stockfileid
ЗАКАЗАТЬ stock. sku ASC

Я уже пытался это:

SELECT * FROM складе
INNER JOIN stockfile ON stock.stockfileid = stockfile.stockfileid
GROUP BY
SKU HAVING stockfile.date = MAX (stockfile.date)
ЗАКАЗАТЬ stock.sku ASC

Но это не сработало

SHOW CREATE TABLE акции:

CREATE TABLE stock (
stockid BIGINT (20) NOT NULL AUTO_INCREMENT,
sku голец (25) NOT NULL,
quantity int (5) NOT NULL ,
creationdate DateTime NOT NULL,
stockfileid SMALLINT (5) без знака NOT NULL, то
touchdate DateTime NOT NULL, то
ПЕРВИЧНЫЙ КЛЮЧ (stockid)
) ДВИГАТЕЛЬ = MyISAM AUTO_INCREMENT = 315169 УМОЛЧАНИЮ CHARSET = latin1

SHOW CREATE TABLE stockfile:

CREATE TABLE stockfile (
stockfileid SMALLINT (5) без знака NOT NULL AUTO_INCREMENT,
filename VARCHAR (25) NOT NULL,
creationdate DateTime УМОЛЧАНИЮ NULL, то
touchdate DateTime УМОЛЧАНИЮ NULL, то
date DateTime УМОЛЧАНИЮ NULL, то
begindate DateTime УМОЛЧАНИЮ NULL, то
enddate DateTime УМОЛЧАНИЮ NULL, то
ПЕРВИЧНЫЙ КЛЮЧ (stockfileid)
) ДВИГАТЕЛЬ = MyISAM AUTO_INCREMENT = 265 DEFAULT CHARSET = latin1

+0

Пожалуйста, отредактируйте ваш вопрос с помощью вывода 'SHOW CREATE TABLE stock' и' SHOW CREATE TABLE stockfile'. –

ответ

6

Это пример часто задаваемые "greatest-n-per-group" вопрос, который мы видим каждую неделю Переполнение стека. Следуйте этому тегу, чтобы увидеть другие подобные решения.

SELECT s.*, f1.* 
FROM stock s 
INNER JOIN stockfile f1 
    ON (s.stockfileid = f1.stockfileid) 
LEFT OUTER JOIN stockfile f2 
    ON (s.stockfileid = f2.stockfileid AND f1.date < f2.date) 
WHERE f2.stockfileid IS NULL; 

Если есть несколько строк в stockfile, которые имеют дату макс, вы получите их обоих в наборе результатов. Чтобы решить эту проблему, вам нужно добавить некоторые условия тай-брейка в соединение на f2.


Благодарим за добавление CREATE TABLE информации. Это очень полезно, когда вы задаете вопросы SQL.

Я вижу из параметров стола AUTO_INCREMENT, что у вас есть 315k строк в stock и только 265 строк в stockfile. Ваша таблица stockfile является родителем в отношении, а таблица stock является дочерним элементом, с столбцом stockfileid, который ссылается на первичный ключ stockfile.

Таким образом, ваш первоначальный вопрос вводит в заблуждение. Вам нужна последняя строка от stock, а не последняя строка от stockfile.

SELECT f.*, s1.* 
FROM stockfile f 
INNER JOIN stock s1 
    ON (f.stockfileid = s1.stockfileid) 
LEFT OUTER JOIN stock s2 
    ON (f.stockfileid = s2.stockfileid AND (s1.touchdate < s2.touchdate 
     OR s1.touchdate = s2.touchdate AND s1.stockid < s2.stockid)) 
WHERE s2.stockid IS NULL; 

Я предполагаю, что вы хотите «последний», чтобы быть относительно touchdate, так что если вы хотите использовать creationdate вместо этого, вы можете сделать изменения.

Я добавил термин к соединению, чтобы он разрешил связи. Я знаю, что вы сказали, что даты «практически уникальны», но, как говорится, «one in a million is next Tuesday».


Хорошо, я думаю, что понимаю, что вы сейчас пытаетесь сделать. Вам нужна самая последняя строка в категории sku, но date, с помощью которой вы можете сравнить их в таблице с привязками stockfile.

SELECT s1.*, f1.* 
FROM stock s1 
JOIN stockfile f1 ON (s1.stockfileid = f1.stockfileid) 
LEFT OUTER JOIN (stock s2 JOIN stockfile f2 ON (s2.stockfileid = f2.stockfileid)) 
    ON (s1.sku = s2.sku AND (f1.date < f2.date OR f1.date = f2.date AND f1.stockfileid < f2.stockfileid)) 
WHERE s2.sku IS NULL; 

Это делает автообъединение из stock к себе, ищет строку с тем же sku и более поздними date. Когда ни один не найден, то s1 содержит самую последнюю строку для ее sku. И каждый экземпляр stock должен присоединиться к своему stockfile, чтобы получить date.


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

CREATE INDEX stock_sku ON stock(sku); 
CREATE INDEX stock_stockfileid ON stock(stockfileid); 
CREATE INDEX stockfile_date ON stockfile(date); 

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

+0

Я знаю, я фактически решил аналогичную проблему благодаря stackoverflow. Но ваш запрос по-прежнему дает мне 315 000 результатов:/ – skerit

+0

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

+0

Много связей? Поле «дата» практически уникально в таблице запасов. На дату может быть около 100 записей в таблице запасов – skerit

0

Есть два распространенных способа сделать это: суб-запрос или автообъединение.

См. this example of selecting the group-wise maximum на сайте MySQL.

Edit, пример с использованием подзапроса:

SELECT stock.stockid, stock.sku, stock.quantity, 
     stockfile.filename, stockfile.date 
FROM stock 
INNER JOIN stockfile ON stock.stockfileid = stockfile.stockfileid 
WHERE stockfile.date = (SELECT MAX(date) FROM stockfile); 
0
select * 
from stock 
where stockfileid in (
      select top 1 stockfileid 
      from stockfile 
      order by date desc 
     ) 
+0

Это не сработает, как есть - вам нужно сопоставить подзапрос. В настоящее время подзапрос вернет только одну строку, и вы получите фондовый файл, а не дату, которую вы действительно на самом деле. –

+0

Это недействительно SQL для MySQL: http://dev.mysql.com/doc/refman/5.4/en/select.html – charstar

+0

Это тоже - нужно использовать 'LIMIT', а не' TOP' –

2

Использование:

SELECT DISTINCT s.stockid, 
     s.sku, 
     s.quantity, 
     sf.filename, 
     sf.date 
    FROM STOCK s 
    JOIN STOCKFILE sf ON sf.stockfileid = s.stockfileid 
    JOIN (SELECT t.stockfileid, 
       MAX(t.date) 'max_date' 
      FROM STOCKFILE t 
     GROUP BY t.stockfileid) x ON x.stockfileid = sf.stockfileid 
           AND x.max_date = sf.date 
+0

Я боюсь, что это все равно дает мне все 315 000 записей. – skerit

+0

Я обновил, чтобы добавить 'DISTINCT', потому что наиболее вероятная причина заключается в том, что строки дублируются из-за JOIN. –

+0

Хм, даже с отличным он все еще дает мне все дубликаты записей. – skerit