【问题标题】:How to replace 2 queries with except如何用except替换2个查询
【发布时间】:2014-03-27 08:18:00
【问题描述】:

我有两个疑问:

SELECT 
      users.id, 
      users.gender, 
      users.status, 
      users.icon_id, 
      users.image_name, 
      coords.lat, 
      coords.lng, 
      users.mess_count 
FROM 
    users 
INNER JOIN 
    coords ON users.id = coords.user_id

然后我选择被屏蔽的用户:

SELECT 
      first_user, 
      second_user 
FROM 
    blocks 
WHERE 
    first_user = $1 OR second_user = $1

我需要从第一个表中选择所有具有坐标且未被阻止的用户,我还需要一些公共信息(性别等)。然后因为我需要两侧阻挡。我必须选择是用户阻止了他,还是他被该用户阻止了。所以 $1 是当前用户,我选择的是我在 block 表中的 id,如果是 - 我从第一个查询中排除另一个用户。

然后在我的编程语言中使用字符串操作,我转换我的字符串以排除我从第二个查询中获得的结果。

我可能可以用EXCEPT 做到这一点,但我不能这样做,因为我只选择了第二个查询的 2 列,我需要更多,最终结果:users.id, users.gender, users.status, users.icon_id, users.image_name, coords.lat, coords.lng, users.mess_count

【问题讨论】:

  • $1 和 $2 是用户名还是用户 ID?
  • @frlan 是用户 ID。
  • 您需要更多的业务逻辑细节。例如,第一个查询只为每条记录返回 一个 个用户的数据,但第二个查询有 两个 个用户每条记录。如果users.id 出现在query 2either 列中,是否要从query 1 中排除所有记录?请具体,最好显示示例输入和输出数据。
  • @MatBailie 我刚刚更新了我的问题。需要您的评论,可以理解吗?

标签: sql postgresql except


【解决方案1】:

有几种方法可以做到这一点,唯一稍微妥协的因素是我相信您想要排除出现在@987654321 的两列中任一中的用户@表。

SQL 传统上使用OR 逻辑的性能较弱,以下查询尝试解决此问题。 (部分是因为它能够更好地利用索引)

SELECT 
  users.id, 
  users.gender, 
  users.status, 
  users.icon_id, 
  users.image_name, 
  coords.lat, 
  coords.lng, 
  users.mess_count 
FROM 
  users 
INNER JOIN
  coords
    ON users.id=coords.user_id
WHERE
      NOT EXISTS (SELECT * FROM blocks WHERE first_user  = users.id AND second_user = $1)
  AND NOT EXISTS (SELECT * FROM blocks WHERE second_user = users.id AND first_user  = $1)


根据 PostgreSQL 的版本,优化器可能在处理相关子查询时效率较低,例如我上面使用的那些。在这种情况下,以下可能会更高效。 (它仍然避免使用 OR。)

SELECT 
  users.id, 
  users.gender, 
  users.status, 
  users.icon_id, 
  users.image_name, 
  coords.lat, 
  coords.lng, 
  users.mess_count 
FROM 
  users 
INNER JOIN
  coords
    ON users.id=coords.user_id
LEFT JOIN
(
   SELECT first_user  AS user_id FROM blocks WHERE second_user = $1
   UNION
   SELECT second_user AS user_id FROM blocks WHERE first_user  = $1
)
  AS blocks
    ON blocks.users_id = users.id
WHERE
  blocks.user_id IS NULL

【讨论】:

  • 你对@Vitap Ramdevputra 建议的NOT IN 有什么看法?
  • @SlowHarry - 它在功能上与NOT EXISTS 方法相同,但在许多 RDBMS 中它可能会更慢,具体取决于您的数据。子查询返回的项目(阻止程序)的数量越多,这一点就越真实。我使用 PostGres 的次数不如我使用其他的多,但我还没有发现 NOT IN 的性能优于 NOT EXISTS,即使它们都得到了最有用的可能索引的支持。
【解决方案2】:

您可以使用blocks 表离开联接,然后使用is null 检查。

SELECT 
      users.id, 
      users.gender, 
      users.status, 
      users.icon_id, 
      users.image_name, 
      coords.lat, 
      coords.lng, 
      users.mess_count 
FROM 
      users 
INNER JOIN coords ON users.id=coords.user_id
LEFT JOIN blocks ON users.id = blocks.first_user OR users.id = blocks.second_user
WHERE blocks.first_user IS NULL

【讨论】:

  • 此查询不使用 $1 参数。
  • $1参数是什么?
  • 看OP,第二个查询有两个引用$1
【解决方案3】:

检查一下,我使用NOT IN 编写了查询。

SELECT 
  users.id, 
  users.gender, 
  users.status, 
  users.icon_id, 
  users.image_name, 
  coords.lat, 
  coords.lng, 
  users.mess_count 
FROM 
  users 
  INNER JOIN coords ON users.id=coords.user_id
  Where 
   users.id NOT IN (SELECT first_user FROM blocks WHERE first_user=$1)
   AND
   users.id NOT IN (SELECT second_user FROM blocks WHERE second_user=$1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-02
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 2016-02-29
    • 1970-01-01
    • 2014-10-30
    相关资源
    最近更新 更多