【问题标题】:Many to many relation, IN operator and possibility of improper results多对多关系、IN 运算符和不正确结果的可能性
【发布时间】:2014-02-14 14:47:01
【问题描述】:

我在创建最佳 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] ";
}

但我认为这是非常糟糕的方式。有没有办法在单个查询中获取用户和指定组?

【问题讨论】:

  • 是否可以更改数据库?你能在这里粘贴两个表的列吗?所以我们有更好的看法?
  • 是的,但我想我会有很多工作要做......
  • 它是:用户、组、消息和用户到组的关系表。我会尽快提供专栏。
  • @Dieter 你能澄清一下改变数据库的意思吗?您是指表结构还是从 Postgres 移出?

标签: php postgresql optimization many-to-many


【解决方案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 替换为usergroup 作为标识符的。

-> SQLfiddle

这样,数组中具有相同序号位置的元素(从逗号分隔的列表转换而来)形成一行。两个数组都需要有相同数量的元素,否则操作将产生笛卡尔积。根据你的描述,这里应该是这样。添加代码以验证是否可能违反该条件。

更清洁的替代品

虽然上述工作可靠,但它是 SRF(设置返回函数)的非标准 Postgres 功能,有些人不赞成。

有更简洁的方法可以做到这一点。即将发布的 9.4 版 Postgres 将发布一个新功能:WITH ORDINALITY,允许更简洁的代码。这个相关的答案证明了这两个:
PostgreSQL unnest() with element number

【讨论】:

  • 难以置信。看起来它适用于我正在使用的 PGSQL 9.1。
猜你喜欢
  • 1970-01-01
  • 2011-09-21
  • 2015-09-16
  • 2019-05-22
  • 1970-01-01
  • 1970-01-01
  • 2021-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多