PostgreSQL查询返回多行而不是一行

问题描述 投票:0回答:2

我有两个表:userprojects,两者之间存在一对多关系。projects表的字段status具有用户的项目状态。

status可以是以下之一:

launched, confirm, staffed, overdue, complete, failed, ended

我想将用户分为两类:

  1. launched阶段中拥有项目的用户
  2. 具有非launched状态项目的用户。

我正在使用以下查询:

SELECT DISTINCT(u.*), CASE 
    WHEN p.status = 'LAUNCHED' THEN 1
    ELSE 2
    END as user_category
FROM users u
LEFT JOIN projects p ON p.user_id = u.id
WHERE (LOWER(u.username) like '%%%'
    OR LOWER(u.personal_intro) like '%%%'
    OR LOWER(u.location) like '%%%'
    OR u.account_status != 'DELETED'
AND system_role=10 AND u.account_status ='ACTIVE')
ORDER BY set_order, u.page_hits DESC
LIMIT 10
OFFSET 0

在以下情况下,我面临重复记录

如果用户具有状态为launched以及overduecompletefailed的项目,则该用户被记录两次,因为CASE中的两个条件都满足该用户。

[请提出一个查询,让处于launched状态的任何项目的用户都将其user_category设置为1user_category 2不应重复使用同一用户。

sql postgresql greatest-n-per-group operator-precedence rails-postgresql
2个回答
4
投票

由于多种原因,该查询可能未按照您认为的那样做

  • DISTINCT,有DISTINCT ON (col1, col2)DISTINCT (u.*)DISTINCT u.*相同。括号只是噪音。

  • AND根据OR绑定在operator precedence之前。我怀疑您想在条件OR一起使用括号吗?还是您需要它?但是无论如何,您不需要在整个WHERE子句中加上括号。

  • 您的表达式LOWER(u.username) LIKE '%%%'没有任何意义。每个非空字符串都符合条件。可以用u.username IS NOT NULL代替。我怀疑您想要其他东西吗?

  • Postgres在字符串处理中是区分大小写。您写出status正在“启动”等,但在查询中使用“ LAUNCHED”。是哪一个?

  • 这个问题缺少几个表资格,这对读者来说是模棱两可的。我填写了我认为合适的内容。

所有东西放在一起,它[[可能像这样工作:

SELECT DISTINCT ON (u.set_order, u.page_hits, u.id) u.* , CASE WHEN p.status = 'LAUNCHED' THEN 1 ELSE 2 END AS user_category FROM users u LEFT JOIN projects p ON p.user_id = u.id WHERE LOWER(u.username) LIKE '%%%' -- ??? OR LOWER(u.personal_intro) LIKE '%%%' OR LOWER(u.location) LIKE '%%%' OR u.account_status != 'DELETED' -- with original logic AND u.system_role = 10 AND u.account_status = 'ACTIVE' ORDER BY u.set_order, u.page_hits DESC, u.id, user_category LIMIT 10
此相关问题的详细说明:

  • 用两个EXISTS semi-joins代替EXISTSDISTINCT ON可能更快:

    CASE


  • 1
    投票
    您可以在SELECT u.* , CASE WHEN EXISTS ( SELECT FROM projects p WHERE p.user_id = u.id AND p.status = 'LAUNCHED') THEN 1 ELSE 2 END AS user_category FROM users u WHERE ( LOWER(u.username) LIKE '%%%' -- ??? OR LOWER(u.personal_intro) LIKE '%%%' OR LOWER(u.location) LIKE '%%%' OR u.account_status != 'DELETED' -- with alternative logic? ) AND u.system_role = 10 -- assuming it comes from users ??? AND u.account_status = 'ACTIVE' AND EXISTS (SELECT 1 FROM projects p WHERE p.user_id = u.id) ORDER BY u.set_order, u.page_hits DESC LIMIT 10; 结果上使用MIN(),并且似乎将DISTINCT删除是一个明智的选择:

    CASE

    由于“启动”为1,因此使用MIN()不仅会强制执行一个结果,而且会优先于“启动”而不是其他状态。
    © www.soinside.com 2019 - 2024. All rights reserved.