如何有效地加入3个表M:N

时间:2011-04-17 13:23:58

标签: database postgresql

我有几张桌子:

应用

id | name | url_key
===================
1  | Hello World | hello-world
2  | Snake 2 | snake-2

开发

id | name | url_key
===================
1  | Mr. Robinson | mr-robinson
2  | Richard | richard
3  | Nokia | nokia

应用-开发-分配

app_id | developer_id
=====================
1      | 1
1      | 2
2      | 3

正如您所看到的,一个应用可能有多个开发人员。

我真正需要的是编写一个PostgreSQL查询来选择所有具有关于相关开发人员的有用信息的应用程序。 例如......这样:

Hello World | 1-hello-world | Mr.Robinson<1-mr-robinson> /and 1 more/
Snake 2     | 2-snake-2     | Nokia<3-nokia>

因此,如果应用程序有一个开发人员,只需将开发人员的名称,url密钥和id附加到应用程序,如果有更多开发人员,请附加第一个并附加“有多少开发人员”的信息。

最重要的是 - 我需要最终过滤结果(例如,不从某些指定的开发者返回应用)。

我知道可以通过为应用程序本身编写第一个查询来解决,然后每行发送下一个查询,但不是很好的方式,我认为......

如果我只是简单地加入表格:

SELECT * FROM apps a
LEFT JOIN apps_developers_assignment ada ON a.id = ada.app_id
LEFT JOIN developers d ON ada.developer_id = d.id

Hello World | 1-hello-world | Mr.Robinson<1-mr-robinson>
Hello World | 1-hello-world | Richard<2-richard>
Snake 2     | 2-snake-2     | Nokia<3-nokia>

它返回重复的应用程序......我不知道如何通过开发人员过滤这些结果(如上所述)。

2 个答案:

答案 0 :(得分:1)

假设您只想过滤掉一个开发人员,则需要传递一个参数。我为此目的调用了这个参数/变量@excludeDevId。

我对T-SQL更熟悉,所以这可能/也需要Postgres中的等效语法。另外,由于左连接为null,我将保留空值 - 从输出中你可能想要COALESCE(可能还有一些其他的输出调整)。这是袖口和未经测试,但应该足以让你至少朝着正确的方向前进:

SELECT 
    a.name AppName, 
    a.id AppId,
    d.id DevId,
    d.url_key Url,
    d.name DevName,
    CAST(agg.dev_count - 1 as VARCHAR) + ' more'
FROM 
    (
    SELECT 
        MAX(ada.developer_id) first_dev_id, 
        COUNT(ada.developer_id) dev_count, 
        app_id
    FROM
        apps_developers_assignment ada 
    WHERE 
        d.id != @excludeDevId
    GROUP BY
        app_id
    ) agg
    INNER JOIN apps a ON a.id = agg.app_id
    LEFT JOIN developers d ON agg.developer_id = d.id

答案 1 :(得分:0)

如果你想使用左连接,你需要把你的条件放在连接上,否则它会创建一个内连接,并且不会返回有null的行...尝试像这样:

SELECT * FROM apps a
LEFT JOIN apps_developers_assignment ada ON a.id = ada.app_id
                                            AND ada.developerid = :devid

LEFT JOIN developers d ON ada.developer_id = d.id

WHERE a.id = :appid