2015-06-09 3 views
0

У меня есть небольшая база данных различных частей и цен на компьютер. Есть 2 стола, детали и цены.Соединительные столы, в которых находятся два столбца

части:

partID  desc  mfgr  timeStamp 
---------- ---------- ---------- ---------- 
1   RAM   Crucial  1 
2   MOBO  MSI   1 
3   I7 970  Intel  1 
1   RAM   Crucial  2 

Цены:

productID qty   price  timeStamp 
---------- ---------- ---------- ---------- 
1   1   50.0  1 
1   2   100.0  1 
1   3   130.0  1 
2   1   140.0  1 
3   1   499.99  1 
3   1   449.99  2 
1   4   150.0  2 
2   1   150.0  2 
1   1   40.0  2 
1   4   200.0  3 

мне нужно, чтобы захватить все из частей, которая имеет самую последнюю метку времени и GROUP_CONCAT (цена) для всех цен, которые соответствуют как partID и метку времени. Таким образом, результат должен выглядеть примерно так:

partID  desc  mfgr  timeStamp  GROUP_CONCAT(price) 
---------- ---------- ---------- ---------- ------------------- 
1   RAM   Crucial  2    150.0,40 
2   MOBO  MSI   1    140.0 
3   I7 970  Intel  1    499.99 

Я действительно близкий, но не совсем правильный. Я попытался

SELECT * FROM Parts INNER JOIN 
    (SELECT partID, MAX(Parts.timeStamp) as maxTS, GROUP_CONCAT(price) FROM 
    Parts, Prices WHERE partID = Prices.productID GROUP BY partID) grouped 
ON Parts.partID = grouped.partID AND Parts.timeStamp = grouped.maxTS; 

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

partID  desc  mfgr  timeStamp partID  maxTS  GROUP_CONCAT(price) 
---------- ---------- ---------- ---------- ---------- ---------- ------------------- 
2   MOBO  MSI   1   2   1   140.0,150.0 
3   I7 970  Intel  1   3   1   449.99,499.99 
1   RAM   Crucial  2   1   2   40.0,50.0,100.0,130 

Так что я изменил мою команду

SELECT * FROM Parts INNER JOIN 
    (SELECT partID, MAX(Parts.timeStamp) AS maxTS, GROUP_CONCAT(price) 
    FROM Parts, Prices 
    WHERE partID = Prices.productID AND (SELECT MAX(parts.timestamp) FROM Parts) = Prices.timeStamp) grouped 
ON Parts.partID = grouped.partID AND Parts.timeStamp = grouped.maxTS; 

Но это совпадение только строки из цен, которые имеют наибольшую временную метку, которая происходит по частям. (Что равно 2)

Что я здесь делаю неправильно?

ответ

2

Ошибка, которую вы делаете, заключается в том, что вы группируете ценовые записи, прежде чем отфильтровывать только те записи, которые вам нужны. Итак, ваш подзапрос grouped будет содержать все цены за partID, и нет возможности их разделить позже, потому что они сгруппированы.

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

Вы говорите:

мне нужно, чтобы захватить все из частей, которая имеет самые недавние TIMESTAMP

Итак, давайте сделаем это. Обратите внимание, что это во многом потребует подзапроса или «поворота», поскольку RDBMS не так хороши в том, что вы можете выбрать строку при условии, которое зависит от других строк (в этом случае выбор строк, где поле является максимальным среди некоторые группы). Мы будем называть этот подзапрос aux, и использовать его для выбора записей из parts, которые соответствуют комбинации partID/timeStamp, который удовлетворяет условию:

select * from parts, 
(select partId, max(timeStamp) maxts from parts group by partId) aux 
where parts.partId = aux.partId and parts.timeStamp = aux.maxts 

Это использует неявное соединения, вы можете переписать этот запрос, используя JOIN синтаксис. Я лично избежать JOIN синтаксис, если я не нужно налево, или другие специальные присоединяется:

select * from parts 
join (select partId, max(timeStamp) maxts from parts group by partId) aux 
on parts.partId = aux.partId and parts.timeStamp = aux.maxts 

Теперь, вы хотите присоединиться к нему с ценами того же ID/времени, но группа цены вместе (как GROUP_CONCAT). Ключ здесь состоит только в том, чтобы выбрать (что происходит перед группировкой) ценовые записи, соответствующие «последним» элементам.

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

select parts.partid, parts.desc, group_concat(prices.price) from 
parts, prices, (
    select partId, max(timeStamp) maxts from parts group by partId) aux 
where 
    parts.partId = aux.partId and 
    parts.timeStamp = aux.maxts and 
    prices.productID = parts.partid and 
    prices.timestamp = parts.timestamp 
group by parts.partid, parts.desc 

Это может быть переписано с использованием JOIN синтаксиса а также:

select parts.partid, parts.desc, group_concat(prices.price) 
from parts 
join (select partId, max(timeStamp) maxts from parts group by partId) aux 
on parts.partId = aux.partId and parts.timeStamp = aux.maxts 
join prices on prices.productID = parts.partid and prices.timestamp = parts.timestamp 
group by parts.partid, parts.desc 

Этот запрос является немного запутанным, и в зависимости от набора данных, это может быть полезно, чтобы переписать его по-другому, чтобы убедиться, что база данных понимает (хорошо для оптимизатора) что фильтруется первый. Мы можем перемещать отфильтрованные «части» в подзапрос своих собственных (назовем его bux), а затем присоединиться к этой с prices таблицей:

select bux.partid, bux.desc, group_concat(prices.price) from prices 
join (
    select parts.partId, parts.desc, aux.maxts 
    from parts join 
    (select partId, max(timeStamp) maxts from parts group by partId) aux 
    on parts.partId = aux.partId and parts.timeStamp = aux.maxts 
) bux 
on prices.productID = bux.partid and prices.timestamp = bux.maxts 
group by bux.partid, bux.desc 

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

http://sqlfiddle.com/#!9/f12c8/10/0

+0

Хм, интересно, я пытался делать * почти * точно, но я использовал присоединиться вместо этого. Это хорошо работает. Просто хочу убедиться, что я правильно понимаю, как это работает, поэтому исправьте меня, если я ошибаюсь. Второй «select» возвращает другую «таблицу», если вы это сделаете, с именем aux, а затем первый «выбор» - из «Детали», «Цены» и «Aux»? – DJMcMayhem

+0

Я расширил ответ, дайте мне знать, если это ответит на ваши вопросы. –

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