如何有效地M:N连接3个表

发布于 2024-11-02 02:01:21 字数 1345 浏览 1 评论 0原文

我有几张表:

应用程序

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 key 和 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>

它会返回重复的应用程序...并且我不知道开发人员如何过滤这些结果(正如我上面写的)。

I have few tables:

Apps:

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

Developers:

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

Apps-Developers-Assignment

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

So as you may see, one app may have more than one developer.

What i actually need is to write a PostgreSQL query to select all apps with some usefull information about related developers.
e.g. sth like this:

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

So if the app has one developer, just append the developer's name, url key and id to the app, if it has more developers, append the first and append the information of "how many developers are there".

And what's most important - i need to eventually filter the results (e.g. not return apps from some specified developer).

I know it can be solved by write first query for apps itself and then send next query per each row, but not the nice way, i think...

If i just simply JOIN the table:

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>

It returns duplicate apps... and i don't know how to filter these results by developer (as i wrote above).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

故人如初 2024-11-09 02:01:21

假设您只想过滤掉一名开发人员,则需要传递一个参数。为此,我将此参数/变量称为 @excludeDevId。

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

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

Assuming you only want to filter out one developer, you will need to pass a parameter. I am calling this parameter/variable @excludeDevId for this purpose.

I am much more familiar to T-SQL, so this may/will also need the equivalent syntax in Postgres. Also, I am leaving nulls as a result of the left join as null--from your output you probably want to COALESCE (probably some other output tweaks as well). This is off the cuff and untested, but should be enough to get you moving in the right direction at least:

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
风渺 2024-11-09 02:01:21

如果您想使用左连接,则需要将条件放在连接上,否则它将创建一个内部连接,并且不会返回包含 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

If you want to use a left join, you'll need to put your condition on the join, otherwise it'll crate an inner join and the rows that have null in won't get returned... try something like this:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文