Это пример часто задаваемого вопроса " наибольшее число групп * ", который мы видим каждую неделю в StackOverflow. Воспользуйтесь этим тегом, чтобы увидеть другие похожие решения.
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
, что у вас есть 315 тыс. Строк в 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
вместо этого, вы можете выполнить редактирование.
Я добавил термин в объединение, чтобы он разрешал связи. Я знаю, что вы сказали, что даты "практически уникальны", но, как говорится, " один на миллион в следующий вторник ."
Хорошо, я думаю, что понимаю, что вы пытаетесь сделать сейчас. Вы хотите самую последнюю строку для 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
.
Комментарий по поводу оптимизации: мне сложно тестировать, потому что у меня нет таблиц, заполненных данными, совпадающими с вашими, но я думаю, у вас должны быть следующие индексы:
CREATE INDEX stock_sku ON stock(sku);
CREATE INDEX stock_stockfileid ON stock(stockfileid);
CREATE INDEX stockfile_date ON stockfile(date);
Я бы предложил использовать EXPLAIN
для анализа запроса без индексов, а затем создавать по одному индексу за раз и повторно анализировать с помощью EXPLAIN
, чтобы увидеть, какой из них дает наиболее прямое преимущество.