连接两列匹配的表

时间:2015-06-09 20:53:48

标签: sql sqlite join inner-join

我有一个包含各种计算机零件和价格的小型数据库。有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)

我在这里做错了什么?

1 个答案:

答案 0 :(得分:2)

您犯的错误是您在过滤掉您需要的条目之前对价格条目进行分组。因此,您的grouped子查询将包含partID的所有价格,之后无法将它们分开,因为它们已分组。

解决这类问题的最佳方法是将您的查询分解为您需要的部分。

你说:

  

我需要从最近的部件中获取所有内容   时间戳

所以,让我们这样做。请注意,这几乎需要一个子查询或“pivot”,因为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