我在创建最佳SQL查询时遇到问题。我有私人消息系统,用户可以向许多用户或用户组发送单个消息。收件人存储在单个文本列中(不要问我为什么我不负责设计),如下所示:
[60,63,103,68]
另外我添加了新的文本列,其中放置了用户所属的组,因此我可以在数据库中作为组:
[55,11,11,0]
现在我想获得所有用户(接收者)及其群组。我有表用户和组ID之间的关系。问题是单个用户可以属于多个组,例如用户60可以在组ID 55和11中。我想以最佳方式进行(可以有50多个接收器存储在列中......)所以我可以写这样的查询:
SELECT u.name, u.last_name, g.group_name
FROM
user u
LEFT JOIN
group g ON u.id = g.user_id
WHERE
u.id IN (".$users.") and
g.id IN (".$groups.")
不幸的是,查询返回的组名可能不正确 - 与我在WHERE中放置的组ID相关联。我可以创建PHP foreach并使用我拥有的ID获取用户及其组:
foreach($user as $key => $single)
{
$sql = "...
where u.id = $single AND g.id = $group[$key] ";
}
但我认为这是非常糟糕的方式。有没有办法在单个查询中获取用户和指定的组?
答案 0 :(得分:1)
由于用户和群组仅通过列表中的序号位置进行关联,因此您需要使用它。
快速而肮脏的方法是unnest()
并行:
SELECT u.name, u.last_name, g.group_name
FROM (
SELECT unnest(string_to_array('3,1,2', ',')::int[]) AS usr_id -- users
, unnest(string_to_array('10,11,12', ',')::int[]) AS grp_id -- groups
) sel
JOIN usr_grp ug USING (usr_id, grp_id)
JOIN usr u USING (usr_id)
JOIN grp g USING (grp_id);
请注意我将SQL key words替换为user
或group
作为标识符。
这样,数组中具有相同序号位置的元素(从逗号分隔列表转换)形成一行。两个数组都需要相同数量的元素,否则操作将导致笛卡尔积。根据你的描述,这应该就是这种情况。添加代码以验证是否可能违反该条件。
虽然上述工作可靠,但它是SRF的非标准Postgres功能(设置返回功能),但有些人不赞成。
有更简洁的方法可以做到这一点。即将发布的Postgres版本9.4将发布一个新功能:WITH ORDINALITY
,允许更清晰的代码。这个相关的答案证明了两者:
PostgreSQL unnest() with element number