如何在PostgreSQL中使用单个SQL命令仅转换表的一部分

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

在PostgreSQL表中,我有一些信息以文本形式存储。取决于类型列所描述的上下文,存储什么类型的信息。该应用程序准备仅通过一个命令获取该行的ID。

当我尝试将信息(bigint存储为字符串)与外部值(例如'9'>'11')进行比较时,我遇到了麻烦。当我尝试强制转换列时,数据库返回错误(并非列中的所有值都是可转换的,例如datetime或普通文本)。另外,当我尝试仅强制转换查询命令的结果时,也会出现强制转换错误。

我通过此命令获得具有可转换行的表:

SELECT information.id as id, item.information::bigint as item
FROM information
INNER JOIN item
ON information.id = item.informationid
WHERE information.type = 'task'

结果行仅显示可强制转换的文本。当我将其放入另一个命令时,将导致错误。

SELECT x.id FROM (
    SELECT information.id as id, item.information::bigint as item
    FROM information
    INNER JOIN item
    ON information.id = item.informationid
    WHERE information.type = 'task'
) AS x
WHERE x.item > '0'::bigint

根据该错误,数据库尝试强制转换表中的所有行。

sql postgresql casting
2个回答
0
投票

这很不幸。尝试使用case表达式:

SELECT inf.id as id,
       (CASE WHEN inf.type = 'task' THEN i.information::bigint END) as item
FROM information inf JOIN
     item i
     ON inf.id = i.informationid
WHERE inf.type = 'task';

0
投票

从技术上讲,这是因为优化器认为WHERE x.item > '0'::bigint是比information.type ='task'更有效的过滤器。因此,在表扫描中,选择WHERE x.item > '0'::bigint条件作为谓词。这种想法没有错,但会让您陷入这种看似不合逻辑的麻烦。

[戈登的建议使用CASE WHEN inf.type = 'task' THEN i.information::bigint END可以避免这种情况,但是将其作为子查询使用可能会破坏您的想法。

我尝试过的一个有趣技巧是使用OUTER APPLY:

select x.* from (select 1 AS dummy) dummy
outer apply (
    SELECT information.id as id, item.information::bigint as item
    FROM information
    INNER JOIN item
    ON information.id = item.informationid
    WHERE information.type = 'task'
) x
WHERE x.item > '0'::bigint

最后,一种更简洁但不太灵活的方法是添加优化器提示以将其关闭以强制优化器按照其编写方式运行查询。

© www.soinside.com 2019 - 2024. All rights reserved.