JOIN 3表和(LIMIT 2行ORDER BY时间DESC)

时间:2011-08-05 12:42:19

标签: mysql join sql-order-by limit

我知道这个问题已被多次询问,但我在实施时遇到了麻烦 我做了一个简洁的例子,因此很容易重现。
我想加入3个表,但在最后一个表上我想限制为2行DESC

CREATE TABLE `cars` (
`car_id` int(11) NOT NULL AUTO_INCREMENT,
`plate` varchar(10) NOT NULL,
`km` int(11) NOT NULL,
`status` tinyint(1) NOT NULL,
PRIMARY KEY (`car_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
INSERT INTO `cars` (`car_id`, `plate`, `km`, `status`) VALUES
(1, 'ABC1234', 130123, 1),
(2, 'DEF1234', 100123, 1),
(3, 'QWE1234', 5000, 1),
(4, 'ASD1234', 3000, 1),
(5, 'ZXC1234', 23000, 0);

CREATE TABLE `cars_to_users` (
`car_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
UNIQUE KEY `car_id` (`car_id`,`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `cars_to_users` (`car_id`, `user_id`) VALUES
(1, 1),
(2, 1),
(3, 2),
(4, 2),
(5, 2);

CREATE TABLE `service` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`car_plate` varchar(10) NOT NULL,
`s_timestamp` int(10) NOT NULL,
`price` double NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=111 ;
INSERT INTO `service` (`id`, `car_plate`, `s_timestamp`, `price`) VALUES
(1, 'ABC1234', 1312300100, 30),
(2, 'DEF1234', 1312300100, 15),
(3, 'QWE1234', 1312300100, 16),
(4, 'ASD1234', 1312300100, 50),
(5, 'ABC1234', 1312300200, 50),
(6, 'DEF1234', 1312300200, 25),
(7, 'QWE1234', 1312300200, 30),
(8, 'ABC1234', 1312300300, 20),
(9, 'ASD1234', 1312300300, 60),
(10, 'ABC1234', 1312300400, 15),
(11, 'ASD1234', 1312300400, 20);

我想要的是这个

car_id  plate  km  car_plate  s_timestamp  price  
3 QWE1234 5000 QWE1234 1312300200 30 
3 QWE1234 5000 QWE1234 1312300100 16 
4 ASD1234 3000 ASD1234 1312300400 20 
4 ASD1234 3000 ASD1234 1312300300 60 

来自s_timestamp DESC排序的user_id = 2的每辆车的“service”表中有2行

ORDER BY s_timestamp LIMIT 2 DESC

我尝试了这个查询,但是给了我“service”

中的所有行
SELECT ctu.user_id, c.car_id, c.plate, c.km, s.car_plate, s.s_timestamp, s.price
FROM cars_to_users ctu 
LEFT JOIN cars c ON  ctu.car_id = c.car_id
LEFT JOIN service s ON c.plate = s.car_plate 
WHERE ctu.user_id = '2' 
AND c.status = 1

如果我添加“GROUP BY c.car_id”我每辆车只能获得1行而不是2我想要

我尝试了很多查询但没有得到我想要的东西。

要记住的是,“服务”表的行数超过900万行,数据量超过示例,并且还会增长。

3 个答案:

答案 0 :(得分:2)

这个答案非常复杂。而且我不确定它在您的数据库上的表现如何。

SELECT ctu.user_id, c.car_id, c.plate, c.km, s.car_plate, s.s_timestamp, s.price
FROM cars_to_users ctu 
LEFT JOIN cars c ON  ctu.car_id = c.car_id
LEFT JOIN service s ON c.plate = s.car_plate
JOIN 
(
  SELECT service.car_plate,max(service.s_timestamp) as s_timestamp
  FROM service
  JOIN 
  (
    SELECT car_plate, max(s_timestamp) as s_timestamp FROM service GROUP BY car_plate
  ) as max_timestamp ON max_timestamp.car_plate = service.car_plate AND service.s_timestamp < max_timestamp.s_timestamp
  GROUP BY service.car_plate
) as max_2_timestamp ON s.car_plate = max_2_timestamp.car_plate AND s.s_timestamp >= max_2_timestamp.s_timestamp
WHERE ctu.user_id = '2' 
AND c.status = 1
ORDER BY s_timestamp DESC


我想你可以先把2个子查询放在临时表中,就像这样

DROP TABLE IF EXISTS max_timestamp;
DROP TABLE IF EXISTS max_2_timestamp;

CREATE TEMPORARY table max_timestamp SELECT car_plate, max(s_timestamp) as s_timestamp FROM service GROUP BY car_plate;

CREATE TEMPORARY table max_2_timestamp
(
  SELECT service.car_plate,max(service.s_timestamp) as s_timestamp
  FROM service
  JOIN max_timestamp ON max_timestamp.car_plate = service.car_plate AND service.s_timestamp < max_timestamp.s_timestamp
  GROUP BY service.car_plate
);

SELECT ctu.user_id, c.car_id, c.plate, c.km, s.car_plate, s.s_timestamp, s.price
FROM cars_to_users ctu 
LEFT JOIN cars c ON  ctu.car_id = c.car_id
LEFT JOIN service s ON c.plate = s.car_plate
JOIN max_2_timestamp ON s.car_plate = max_2_timestamp.car_plate AND s.s_timestamp >= max_2_timestamp.s_timestamp
WHERE ctu.user_id = '2' 
AND c.status = 1
ORDER BY s_timestamp DESC;


编辑:另一种选择

您只有一个查询,但我无法检查您的系统中是否高效。·
让我们创建一个函数,为s_timestamp

中的每个car_plate检索最近的第ServiceCREATE FUNCTION LatestService (car_plate varchar(10)) RETURNS int(10) RETURN (SELECT s_timestamp FROM service s WHERE s.car_plate=`car_plate` ORDER BY s.s_timestamp desc LIMIT 1,1);
SELECT ctu.user_id, c.car_id, c.plate, c.km, s.car_plate, s.s_timestamp, s.price
FROM cars_to_users ctu 
LEFT JOIN cars c ON  ctu.car_id = c.car_id
LEFT JOIN service s ON c.plate = s.car_plate 
WHERE ctu.user_id = '2' 
AND c.status = 1
AND s.s_timestamp >= LatestService(s.car_plate);

然后您可以使用该功能执行查询。

{{1}}

答案 1 :(得分:0)

按一些ID排序,然后添加'HAVING COUNT(some_id)&lt; 2'

http://www.java2s.com/Code/SQL/Select-Clause/UseCOUNTGROUPandHAVING.htm

答案 2 :(得分:0)

替换

LEFT JOIN service s ON c.plate = s.car_plate 

LEFT JOIN service s on s.id 
  in (SELECT s2.id FROM service s2
      WHERE s2.car_plate=c.plate
      ORDER BY s2.s_timestamp DESC LIMIT 2)

我知道这可以在MS Sql Server中使用,而不是100%确定mysql。

(编辑)如下所述,它没有。解决方法有点丑陋(但不是太糟糕),并在此处描述:

http://forums.mysql.com/read.php?10,416311,416461#msg-416461