SQL:列出用户及其 phone 号码和电子邮件地址
SQL: list users with their phone numbers and email addresses
我想在 PostgreSQL 中进行查询,其中列出我的用户及其电子邮件地址和 phone 数字(以逗号分隔),如下所示:
| user1 | email1@mail.com, email2@mail.com | +3612123123, +3623234234 |
表格是:
user - stores the user's data
user_email - stores the user's email addresses
user_phone - stores the user's phone numbers
我试过 obvius:
SELECT user.id, user.name
(
SELECT array_agg(user_email.email)
FROM user_email
WHERE user_email.user_id = user.id
) AS EmailAddresses,
(
SELECT array_agg(user_phone.phone)
FROM user_phone
WHERE user_phone.user_id = user.id
) AS PhoneNumbers
FROM user
ORDER BY user.id
但这会导致荒谬的查询时间(34 秒)。
比我试过:
SELECT user.id, user.name, array_agg(user_email.email), array_agg(user_phone.phone)
FROM user
LEFT JOIN user_email ON user_email.user_id = user.id
LEFT JOIN user_phone ON user_phone.user_id = user.id
GROUP BY user.id
ORDER BY user.id
这会产生非常好的查询时间(大约 100 毫秒)。
但通过这种方式,它列出了 phone 号码和电子邮件地址的每个组合。因此,如果我有 3 个电子邮件地址和 3 个 phone 号码,那么它会列出 9 个电子邮件地址(每个地址的三倍)和 9 个 phone 号码。
有没有一种有效的方法来做我想做的事?
或者DISTINCT
SELECT DISTINCT user.id, user.name, array_agg(user_email.email), array_agg(user_phone.phone)
FROM user
LEFT JOIN user_email ON user_email.user_id = user.id
LEFT JOIN user_phone ON user_phone.user_id = user.id
GROUP BY user.id
ORDER BY user.id
或INNER
加入
SELECT user.id, user.name, array_agg(user_email.email), array_agg(user_phone.phone)
FROM user
INNER JOIN user_email ON user_email.user_id = user.id
INNER JOIN user_phone ON user_phone.user_id = user.id
GROUP BY user.id
ORDER BY user.id
或两者兼而有之
SELECT DISTINCT user.id, user.name, array_agg(user_email.email), array_agg(user_phone.phone)
FROM user
INNER JOIN user_email ON user_email.user_id = user.id
INNER JOIN user_phone ON user_phone.user_id = user.id
GROUP BY user.id
ORDER BY user.id
DISTINCT
也可以在 aggregate expressions 中使用:
SELECT "user".id, name, array_agg(DISTINCT email) emails, array_agg(DISTINCT phone) phones
FROM "user"
LEFT JOIN user_email ON user_email.user_id = "user".id
LEFT JOIN user_phone ON user_phone.user_id = "user".id
GROUP BY "user".id
ORDER BY "user".id;
注意:如果您只需要逗号分隔的列表,您可能需要使用 string_agg()
而不是 array_agg()
。
我想在 PostgreSQL 中进行查询,其中列出我的用户及其电子邮件地址和 phone 数字(以逗号分隔),如下所示:
| user1 | email1@mail.com, email2@mail.com | +3612123123, +3623234234 |
表格是:
user - stores the user's data
user_email - stores the user's email addresses
user_phone - stores the user's phone numbers
我试过 obvius:
SELECT user.id, user.name
(
SELECT array_agg(user_email.email)
FROM user_email
WHERE user_email.user_id = user.id
) AS EmailAddresses,
(
SELECT array_agg(user_phone.phone)
FROM user_phone
WHERE user_phone.user_id = user.id
) AS PhoneNumbers
FROM user
ORDER BY user.id
但这会导致荒谬的查询时间(34 秒)。 比我试过:
SELECT user.id, user.name, array_agg(user_email.email), array_agg(user_phone.phone)
FROM user
LEFT JOIN user_email ON user_email.user_id = user.id
LEFT JOIN user_phone ON user_phone.user_id = user.id
GROUP BY user.id
ORDER BY user.id
这会产生非常好的查询时间(大约 100 毫秒)。 但通过这种方式,它列出了 phone 号码和电子邮件地址的每个组合。因此,如果我有 3 个电子邮件地址和 3 个 phone 号码,那么它会列出 9 个电子邮件地址(每个地址的三倍)和 9 个 phone 号码。
有没有一种有效的方法来做我想做的事?
或者DISTINCT
SELECT DISTINCT user.id, user.name, array_agg(user_email.email), array_agg(user_phone.phone)
FROM user
LEFT JOIN user_email ON user_email.user_id = user.id
LEFT JOIN user_phone ON user_phone.user_id = user.id
GROUP BY user.id
ORDER BY user.id
或INNER
加入
SELECT user.id, user.name, array_agg(user_email.email), array_agg(user_phone.phone)
FROM user
INNER JOIN user_email ON user_email.user_id = user.id
INNER JOIN user_phone ON user_phone.user_id = user.id
GROUP BY user.id
ORDER BY user.id
或两者兼而有之
SELECT DISTINCT user.id, user.name, array_agg(user_email.email), array_agg(user_phone.phone)
FROM user
INNER JOIN user_email ON user_email.user_id = user.id
INNER JOIN user_phone ON user_phone.user_id = user.id
GROUP BY user.id
ORDER BY user.id
DISTINCT
也可以在 aggregate expressions 中使用:
SELECT "user".id, name, array_agg(DISTINCT email) emails, array_agg(DISTINCT phone) phones
FROM "user"
LEFT JOIN user_email ON user_email.user_id = "user".id
LEFT JOIN user_phone ON user_phone.user_id = "user".id
GROUP BY "user".id
ORDER BY "user".id;
注意:如果您只需要逗号分隔的列表,您可能需要使用 string_agg()
而不是 array_agg()
。