2013-03-11 51 views
1

的加入行條件我有兩個表:MySQL的 - 從右表

mysql> select * from orders; 
+------+---------------------+------------+---------+ 
| id | created_at   | foreign_id | data | 
+------+---------------------+------------+---------+ 
| 1 | 2010-10-10 10:10:10 |   3 | order 1 | 
| 4 | 2010-10-10 00:00:00 |   6 | order 4 | 
| 5 | 2010-10-10 00:00:00 |   7 | order 5 | 
+------+---------------------+------------+---------+ 

mysql> select * from activities; 
+------+---------------------+------------+------+ 
| id | created_at   | foreign_id | verb | 
+------+---------------------+------------+------+ 
| 1 | 2010-10-10 10:10:10 |   3 | get | 
| 2 | 2010-10-10 10:10:15 |   3 | set | 
| 3 | 2010-10-10 10:10:20 |   3 | put | 
| 4 | 2010-10-10 00:00:00 |   6 | get | 
| 5 | 2010-10-11 00:00:00 |   6 | set | 
| 6 | 2010-10-12 00:00:00 |   6 | put | 
+------+---------------------+------------+------+ 

現在我需要在foreign_idorders加入activities:只選擇一個活動(如果存在)爲每個順序, ABS(TIMESTAMPDIFF(SECOND, orders.created_at, activities.created_at))是最小的。例如。訂單和活動大約在同一時間創建。

+----------+---------+---------------------+-------------+------+---------------------+ 
| order_id | data | order_created_at | activity_id | verb | activity_created_at | 
+----------+---------+---------------------+-------------+------+---------------------+ 
|  1 | order 1 | 2010-10-10 10:10:10 |   1 | get | 2010-10-10 10:10:10 | 
|  4 | order 4 | 2010-10-10 00:00:00 |   4 | get | 2010-10-10 00:00:00 | 
|  5 | order 5 | 2010-10-10 00:00:00 |  NULL | NULL | NULL    | 
+----------+---------+---------------------+-------------+------+---------------------+ 

以下查詢生成包含所需行的一組行。如果包含GROUP BY語句,則無法控制activities中的哪一行加入。

SELECT o.id AS order_id 
    , o.data AS data 
    , o.created_at AS order_created_at 
    , a.id AS activity_id 
    , a.verb AS verb 
    , a.created_at AS activity_created_at 
FROM orders AS o 
LEFT JOIN activities AS a ON a.foreign_id = o.foreign_id; 

是否可以寫這樣的查詢?理想情況下,我想避免使用group by,因爲此部分是大型報告querty的一部分。

+0

你想做什麼做用這行代碼:'ABS(TIMESTAMPDIFF(SECOND,orders.created_at,activities.created_at))'? – 2013-03-11 15:02:42

+0

我想盡量減少這個值。例如。如果訂單已在11:00創建,並且有三項活動(1,09:00),(2,10:00),(3,11:00),(3,12:00),我希望第三項活動。該行將返回創建或訂單與活動之間的秒數 – 2013-03-11 15:05:45

回答

1

因爲這兩個表中引用了一些神祕的外鍵有與下面的查詢錯誤的潛力,但它可能給你一個原則,你可以爲你的目的適應......

DROP TABLE IF EXISTS orders; 

CREATE TABLE orders 
(id INT NOT NULL PRIMARY KEY 
,created_at DATETIME NOT NULL 
,foreign_id INT NOT NULL 
,data VARCHAR(20) NOT NULL 
); 

INSERT INTO orders VALUES 
(1 ,'2010-10-10 10:10:10',3 ,'order 1'), 
(4 ,'2010-10-10 00:00:00',6 ,'order 4'), 
(5 ,'2010-10-10 00:00:00',7 ,'order 5'); 

DROP TABLE IF EXISTS activities; 

CREATE TABLE activities 
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY 
,created_at   DATETIME NOT NULL 
,foreign_id INT NOT NULL 
,verb VARCHAR(20) NOT NULL 
); 

INSERT INTO activities VALUES 
(1,'2010-10-10 10:10:10',3,'get'), 
(2,'2010-10-10 10:10:15',3,'set'), 
(3,'2010-10-10 10:10:20',3,'put'), 
(4,'2010-10-10 00:00:00',6,'get'), 
(5,'2010-10-11 00:00:00',6,'set'), 
(6,'2010-10-12 00:00:00',6,'put'); 

SELECT o.id order_id 
    , o.data 
    , o.created_at order_created_at  
    , a.id activity_id 
    , a.verb 
    , a.created_at activity_created_at 
    FROM activities a 
    JOIN orders o 
    ON o.foreign_id = a.foreign_id 
    JOIN 
    (SELECT a.foreign_id 
      , MIN(ABS(TIMEDIFF(a.created_at,o.created_at))) x 
     FROM activities a 
     JOIN orders o 
      ON o.foreign_id = a.foreign_id 
     GROUP 
      BY a.foreign_id 
    ) m 
    ON m.foreign_id = a.foreign_id 
    AND m.x = ABS(TIMEDIFF(a.created_at,o.created_at)) 
UNION DISTINCT 
SELECT o.id 
    , o.data 
    , o.created_at 
    , a.id 
    , a.verb 
    , a.created_at 
    FROM orders o 
    LEFT 
    JOIN activities a 
    ON a.foreign_id = o.foreign_id 
WHERE a.foreign_id IS NULL; 
; 

+----------+---------+---------------------+-------------+------+---------------------+ 
| order_id | data | order_created_at | activity_id | verb | activity_created_at | 
+----------+---------+---------------------+-------------+------+---------------------+ 
|  1 | order 1 | 2010-10-10 10:10:10 |   1 | get | 2010-10-10 10:10:10 | 
|  4 | order 4 | 2010-10-10 00:00:00 |   4 | get | 2010-10-10 00:00:00 | 
|  5 | order 5 | 2010-10-10 00:00:00 |  NULL | NULL | NULL    | 
+----------+---------+---------------------+-------------+------+---------------------+ 
+0

謝謝,這非常有幫助。我結束了修改查詢一點點:SELECT o.id,o.data,a.verb,MX 'FROM級O \t LEFT JOIN( \t \t SELECT o2.id o_id \t \t,a2.id A_ID \t \t,MIN(ABS(TIMESTAMPDIFF(SECOND,a2.created_at,o2.created_at)))× \t \t FROM訂單O2 \t \t JOIN活動a2爲 \t \t \t ON o2.foreign_id = a2.foreign_id \t \t GROUP \t \t \t BY o2.foreign_id \t)米 \t \t ON m.o_id = o.id \t LEFT JOIN活動 \t \t ON m.a_id = a.id' – 2013-03-11 16:53:46

+0

行動,我沒有注意你的編輯。我修改後的查詢似乎達到了相同的結果,並且比您的更簡單。 – 2013-03-11 16:56:19

+0

鑑於o2.foreign_id = a2.foreign,我沒有看到選擇a2.id的要點。我不認爲我們的查詢在邏輯上是相同的,所以他們會在大數據集上產生不同的結果。但只有你可以說哪一個是正確的。而且,兩者都會因時間差異而掙扎。轉換爲秒,做數學,然後轉換回來可能會更好。在表現方面,我有一個鬼鬼祟祟的懷疑,你的確比我的快 - 但我不確定。 – Strawberry 2013-03-23 12:12:19