我知道这个问题已被多次询问,但我在实施时遇到了麻烦
我做了一个简洁的例子,因此很容易重现。
我想加入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万行,数据量超过示例,并且还会增长。
答案 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
检索最近的第Service
个CREATE 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