就像错误消息说:
for SELECT DISTINCT, ORDER BY expressions must appear in select list
这是一个表达式:
CASE WHEN users.id=3 THEN 0 WHEN users.id=5 THEN 1 END
在执行SELECT DISTINCT users.* FROM ... 时不能按它排序,因为这仅允许出现在SELECT 列表中的ORDER BY 表达式。
通常情况下,DISTINCT 的最佳解决方案是一开始就不要使用它。如果您不重复行,则以后不必对它们进行重复数据删除。见:
在您的情况下,请使用 EXISTS 半联接(表达式/子查询)而不是联接。这避免了重复。假设表 users 中有不同的行,DISTINCT 就失业了。
SELECT u.*
FROM users u
WHERE u.deleted_at IS NULL
AND u.company_id = 2
AND EXISTS (
SELECT FROM areas_users au JOIN areas a ON a.id = au.area_id
WHERE au.user_id = u.id
AND a.id IN (2, 4, 5)
AND a.deleted_at IS NULL
)
ORDER BY CASE u.id WHEN 3 THEN 0
WHEN 5 THEN 1 END, u.id, 1; -- ①
按您的要求做,而且通常更快。
使用simple ("switched") CASE 语法。
①还有一点难看。在ORDER BY 中使用位置引用可以是方便的简短语法。但是,虽然您有SELECT *,但这是一个非常糟糕的主意。如果基础表中列的顺序发生变化,您的查询将被静默更改。拼出这个用例中的列!
(通常,您首先不需要SELECT *,而只需要选择列。)
如果您的 ID 列保证为正数,这会更快一些:
...
ORDER BY CASE u.id WHEN 3 THEN -2
WHEN 5 THEN -1
ELSE u.id END, <name_of_first_column>
我必须使用DISTINCT
(真的吗?)如果你坚持:
SELECT DISTINCT CASE u.id WHEN 3 THEN -2 WHEN 5 THEN -1 ELSE u.id END AS order_column, u.*
FROM users u
JOIN areas_users au ON au.user_id = u.id
JOIN areas a ON a.id = au.area_id
WHERE u.deleted_at IS NULL
AND u.company_id = 2
AND a.id IN (2, 4, 5)
AND a.deleted_at IS NULL
ORDER BY 1, <name_of_previously_first_column>; -- now, "ORDER BY 1" is ok
您会在结果中获得额外的列 order_column。您可以将其包装在具有不同 SELECT 的子查询中...
只是一个概念证明。不要使用这个。
还是DISTINCT ON?
SELECT DISTINCT ON (CASE u.id WHEN 3 THEN -2 WHEN 5 THEN -1 ELSE u.id END, <name_of_first_column>)
u.*
FROM users u
JOIN areas_users au ON au.user_id = u.id
JOIN areas a ON a.id = au.area_id
WHERE u.deleted_at IS NULL
AND u.company_id = 2
AND a.id IN (2, 4, 5)
AND a.deleted_at IS NULL
ORDER BY CASE u.id WHEN 3 THEN -2 WHEN 5 THEN -1 ELSE u.id END, <name_of_first_column>;
这无需返回额外的列即可工作。仍然只是概念证明。不要用,EXISTS 查询要便宜很多。
见: