2011-08-05 66 views
5

我知道這個問題已經被問了很多次了,但是我在執行時遇到了問題。
我做了一個減少的例子,所以很容易重現。
我想加入3個表,但在最後一個我想限制在2行DESC
加入3個表格和(限制2行ORDER BY time 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 

2行來自「s ervice「表中USER_ID的每一輛= 2的s_timestamp降序排列

ORDER BY s_timestamp LIMIT 2 DESC 

我嘗試此查詢,但給我的一切,從行‘服務’

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Ç .car_id」我只得到1行每車,而不是2我想

我嘗試了很多疑問,但沒有得到我想要的東西。

要記住一件事是,表中的「服務」擁有超過900萬行的數據超出例子,長大。

+0

你使用的mysql版本是什麼,你說的限制不適用於你的版本? – reggie

+0

如果你能夠使用我的語句,使用臨時表應該使它快一點。 – ace

+0

@ace您的解決方案也很棒。但是,如果通過子查詢可以達到同樣的效果,並且子查詢/臨時表中要檢索的行數只有2個,那麼爲什麼不使用子查詢。 – reggie

回答

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_plateService

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); 
+0

我查詢中的複雜(也許是愚蠢的?)部分是爲每個car_plate獲取2nd_max時間戳。由於目前我無法想到這樣做,所以我必須運行max(timestamp)兩次,第二個max(timestamp)小於第一個max(timestamp)。一旦你有第二個最大時間戳,你可以生成查詢。如果您打算取得前三名或以上,我的獲得結果集的方式非常可怕。 :) – ace

+0

第一個工作,因爲我想要的例子,但在現實生活中的表(9mil行)需要約35秒complite - 所以它超出了範圍。如果我從fisrt 2表中獲取car_plates,併爲每個板塊創建一個PHP foreach循環,例如(SELECT * FROM service WHERE car_plate ='$ plate'ORDER BY timestamp_3 DESC LIMIT 2)我有大約5秒的時間來完成4輛汽車,但是我不想讓4 + 1查詢,但1查詢,我認爲5secs也可以優化。 – madnet

+0

生成臨時表是否也需要太長時間? – ace

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

+0

它在MySQL 5.1.51中有這個錯誤'錯誤代碼:1235 這個版本的MySQL還不支持'LIMIT&IN/ALL/ANY/SOME子查詢' – ace

+0

尼斯嘗試但不工作。像@ace說的錯誤 – madnet

+0

發佈後,我在查看引用以查看它是否被支持,並且也看到它不是。可能有解決方法。如果有一個並不複雜,我會編輯。 – hatchet