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
中的 case
或 select
计算为 null
,但不允许文字,除非强制转换为某些内容可排序。
我有以下 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
解释:
您的 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
中的 case
或 select
计算为 null
,但不允许文字,除非强制转换为某些内容可排序。