2014-04-10 71 views
1

首先,我必須爲壞主題文本道歉,但我沒有任何更好的主意。也許正因爲如此,我在搜索網絡時找不到解決方案。PostgreSQL選擇主記錄並顯示特定記錄的詳細信息列

我有2個表:主人和細節誰當然有外鍵掌握。我想從master和fields中的所有行和所有字段中獲取master中每一行的特定記錄的詳細信息(讓我們說一些列的順序)。

我想是這樣的:

SELECT master.id, master.title, temp2.master_id, temp2.datetime, temp2.title_details 
FROM master 
LEFT JOIN (SELECT master_id, datetime, title AS title_details FROM details ORDER BY datetime DESC) temp2 ON temp2.master_id=master.id 

//and this: 
SELECT master.id, master.title, 
(SELECT master_id, datetime, title AS title_details FROM details WHERE master.id=details.master_id ORDER BY datetime DESC) 
FROM master 
//but of course: subquery must return only one column 

但是,這是行不通的。

例子就是我想做的事:

Master: 
id title 
1 test 
2 blab 
3 something 

Details: 
id master_id datetime title 
1 1   2004-... t: 1.1 
2 1   2005-... t: 2.1 
3 1   2006-... t: 3.1 
4 2   2004-... t: 4.2 
5 2   2005-... t: 5.2 
6 3   2006-... t: 6.3 

Expected output: 
id title  datetime title_details 
1 test  2006-...  t: 3.1 
2 blab  2005-...  t: 5.2 
3 something 2006-...  t: 6.3 

因爲它是我很難解釋我所需要的,這裏是我不想做的PHP代碼(從頭部):

$q = Database::$DB->prepare("SELECT * FROM master"); 
$q2 = Database::$DB->prepare("SELECT * FROM details WHERE master_id=? ORDER BY datetime DESC LIMIT 1"); 
$rows = $q->execute(); 
foreach ($rows as $row) 
{ 
    $q2->execute($row->id); 
    $row->AdditionalFields = $q2->fetch(); 
} 

換句話說,我不想遍歷所有主控行併爲特定的一條記錄(last - ORDER BY datetime)詳細選擇數據。

我嘗試了所有不同的工會,聯接和子查詢,但沒有成功。

編輯(在不同的答案評論):

實際的查詢是:

SELECT DISTINCT ON (todo_topics.id) todo_topics.id, todo_topics.user_id, users.username AS author, todo_topics.title, todo_topics.datetime_created, todo_topics.version, todo_topics.todo_status_id, todo_statuses.icon_image, 
    todo_topics.version_status_changed, todo_posts.text, u.username AS last_poster, todo_posts.user_id as last_poster_id 
FROM todo_topics 
LEFT JOIN todo_statuses ON todo_statuses.id = todo_topics.todo_status_id 
LEFT JOIN users ON users.id = todo_topics.user_id 
LEFT JOIN todo_posts ON todo_topics.id=todo_posts.todo_topic_id 
LEFT JOIN users u ON u.id = todo_posts.user_id 
ORDER BY todo_topics.id, todo_posts.datetime_created DESC 

「總運行時間:0.863毫秒」

SELECT 
     todo_topics.id, todo_topics.user_id, users.username AS author, todo_topics.title, todo_topics.datetime_created, todo_topics.version, todo_topics.todo_status_id, todo_statuses.icon_image, 
     todo_topics.version_status_changed, todo_posts.text, u.username AS last_poster, todo_posts.user_id as last_poster_id 
    FROM 
     todo_topics 
     LEFT JOIN todo_statuses ON todo_statuses.id = todo_topics.todo_status_id 
    LEFT JOIN users ON users.id = todo_topics.user_id 

    INNER JOIN 
    (
     SELECT 
     *, 
     ROW_NUMBER() OVER (PARTITION BY todo_topic_id ORDER BY datetime_created DESC) AS ordinal 
     FROM 
     todo_posts 
    ) 
     AS todo_posts 
     ON todo_posts.todo_topic_id = todo_topics.id 
    LEFT JOIN users u ON u.id = todo_posts.user_id 
    WHERE 
     todo_posts.ordinal = 1 

「總運行時間:1.281毫秒「

SELECT 
    todo_topics.id, todo_topics.user_id, users.username AS author, todo_topics.title, todo_topics.datetime_created, todo_topics.version, todo_topics.todo_status_id, todo_statuses.icon_image, 
    todo_topics.version_status_changed, todo_posts.text, u.username AS last_poster, todo_posts.user_id as last_poster_id 
FROM 
    todo_topics 
LEFT JOIN todo_statuses ON todo_statuses.id = todo_topics.todo_status_id 
LEFT JOIN users ON users.id = todo_topics.user_id 
INNER JOIN 
(
    SELECT 
    todo_topic_id, 
    MAX(datetime_created) AS max_datetime 
    FROM 
    todo_posts 
    GROUP BY 
    todo_topic_id 
) 
    AS details_lookup 
    ON details_lookup.todo_topic_id = todo_topics.id 
INNER JOIN 
    todo_posts 
    ON todo_posts.todo_topic_id = details_lookup.todo_topic_id 
    AND todo_posts.datetime_created = details_lookup.max_datetime 
LEFT JOIN users u ON u.id = todo_posts.user_id 

「總運行時間:1.143毫秒」

如果有人想知道這是什麼時候的具體硬件是指:

該數據庫實驗(在每個表中的記錄數 - < 100)在Windows 7上運行本地主機,英特爾I7 3,4GHz,16GB內存和PostgreSQL 9.3.4(默認安裝)

+0

對於更有意義的測試,您需要填充表格。不要忘記索引。當表增長時,這些變得越來越重要。按照我的答案中的鏈接瞭解更多關於擬合指數的信息。 –

回答

2

簡單與DISTINCT ON

SELECT DISTINCT ON (m.id) 
     m.*, d.datetime, d.title AS title_details 
FROM master m 
LEFT JOIN details d ON d.master_id = m.id 
ORDER BY m.id, d.datetime DESC; 

假設master.id是主鍵和details.datetimeNOT NULL
詳細說明:
Select first row in each GROUP BY group?

小心,如果datetime可以爲NULL。在這種情況下,您可能需要NULLS LAST

+0

我想你的意思是: SELECT DISTINCT ON(m.id) M *,d.datetime,d.title AS title_details 從主機M LEFT JOIN細節d在d.master_id = m.id ORDER BY。 m.id,d.datetime DESC 爲什麼(如果)您的解決方案比@MatBailie更好 – Makla

+0

@Makla:正確。應用。排序順序取決於您想要選擇的行。我現在在你的PHP代碼中看到:你想按'datetime'排序。這個例子適用於任何方式。爲什麼它更好?更短,更快。只需使用'EXPLAIN ANALYSE'進行測試就可以親眼看到,您不必爲此接受我的話。 –

+0

確實如此。 – Makla

2
SELECT 
    * 
FROM 
    master 
INNER JOIN 
(
    SELECT 
    *, 
    ROW_NUMBER() OVER (PARTITION BY master_id ORDER BY datetime DESC) AS ordinal 
    FROM 
    details 
) 
    AS details 
    ON details.master_id = master.id 
WHERE 
    details.ordinal = 1 

或者......

SELECT 
    * 
FROM 
    master 
INNER JOIN 
(
    SELECT 
    master_id, 
    MAX(datetime) AS max_datetime 
    FROM 
    details 
    GROUP BY 
    master_id 
) 
    AS details_lookup 
    ON details_lookup.master_id = master.id 
INNER JOIN 
    details 
    ON details.master_id = details_lookup.master_id 
    AND details.datetime = details_lookup.max_datetime 
相關問題