ORDER BY 中的最后一个案例执行不正确 postgres

Last case in ORDER BY executes incorrectly postgres

我有以下 postgres 存储函数。 ORDER BY returns 数据中的最后一个 CASE WHEN 排序不正确。但是,类似的第二个 CASE WHEN 按预期工作。 我仔细检查了 sort_column 和 sort_direction 是否正确。感谢任何帮助

DB Fiddle: https://dbfiddle.uk/?rdbms=postgres_14&fiddle=32ad76d21a9cb97518b92acf58ddf803

    CREATE OR REPLACE FUNCTION find_experts(BIGINT, _sort_column VARCHAR(256), _sort_direction VARCHAR(256)) 
    RETURNS TABLE (
    user_id BIGINT,
    name VARCHAR(256),
    email VARCHAR(256),
    email_validated BOOLEAN,
    is_verified BOOLEAN,
    rating FLOAT,
    is_promoted BOOLEAN,
    registry_date TIMESTAMP,
    picture VARCHAR(256),
    price FLOAT,
    biography VARCHAR(2028),
    short_bio VARCHAR(1000),
    timeslots VARCHAR(256)[],
    timezone VARCHAR(256)
) AS $$
    SELECT users.user_id, users.name, users.email, users.email_validated, users.is_verified, users.rating, users.is_promoted, users.registry_date,
    user_settings.picture, user_settings.price, user_settings.biography, user_settings.short_bio, user_settings.timeslots, user_settings.timezone
    FROM users 
    LEFT JOIN user_settings ON (users.user_id=user_settings.user_id)
    WHERE users.user_id IN 
    (SELECT user_id FROM users_tech) AND
    active_role='expert' AND price IS NOT NULL
    ORDER BY 
    CASE WHEN _sort_column = 'rating' AND _sort_direction = 'DESC' THEN rating END DESC,
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'ASC' THEN price END ASC, rating ASC, registry_date ASC,
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'DESC' THEN price END DESC, rating DESC, registry_date ASC
    OFFSET ( - 1) * 10
    LIMIT 10
$$ LANGUAGE SQL;

函数是这样执行的:

pool.query(`SELECT * FROM find_experts(, , )`, [1, 'price', 'DESC'])

实际结果:

250
12
11
102
43
856
21
34
63
85

预期结果:

856
250
102
85
63
43
34
21
12
11

修复:

您需要将所有选项包装在 order by 子句中的 case 语句中,以使其按预期工作:

ORDER BY 
    CASE WHEN _sort_column = 'rating' AND _sort_direction = 'DESC' THEN rating END DESC,
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'ASC' THEN price END ASC, 
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'ASC' THEN rating END ASC, 
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'ASC' THEN registry_date END ASC,
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'DESC' THEN price END DESC, 
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'DESC' THEN rating END DESC, 
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'DESC' THEN registry_date END ASC

或切换到 plpgsql 和动态 sql,仅 concatenate your desired order by column and 。 这是你的 db<>fiddle,已修复。

解释:

您的 case 语句构成独立的 order by 子句。我认为您可能会假设该部分中的每一行都是不同的情况,但它们实际上最终作为 order by 的半恒定列集,因此它们的格式更有意义:

ORDER BY 
    CASE WHEN _sort_column = 'rating' AND _sort_direction = 'DESC' THEN rating END DESC,--order column 1, sometimes skipped
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'ASC' THEN price END ASC, --order column 2, sometimes skipped
    rating ASC,        --order column 3, never skipped
    registry_date ASC, --order column 4, never skipped
    CASE WHEN _sort_column = 'price' AND _sort_direction = 'DESC' THEN price END DESC, --order column 5, sometimes skipped
    rating DESC,       --order column 6, never skipped
    registry_date ASC  --order column 7, never skipped

并且以 CASE 开头的每一行最终要么是您想要的,要么是 null,因为您没有指定 else 块。 Order by 将跳过那些评估为 null 的 case 语句,因此在您的示例调用中,它最终像这样

ORDER BY 
    null::integer DESC, --skipped
    null::integer ASC, --skipped
    rating ASC, 
    registry_date ASC,
    price DESC, 
    rating DESC, 
    registry_date ASC

请注意,PostgreSQL 允许将 order by 中的 caseselect 计算为 null,但不允许文字,除非强制转换为某些内容可排序。