2

这是我的 SQL 查询:


SELECT (CASE (elapsed_time_from_first_login IS NULL) 
                        WHEN true THEN 0 
                        ELSE elapsed_time_from_first_login END) 
FROM (
   SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) 
   FROM radacct
   WHERE UserName = 'test156') AS elapsed_time_from_first_login;

当我执行上述查询时,我收到此错误:

错误:CASE 类型记录和整数无法匹配

从错误消息中,我了解到PostgreSQL将第二个选择分别elapsed_time_from_first_login作为一行,即使它始终是单个值(因为 min() 函数)。

问题:您对如何处理此查询有一些建议吗?

4

4 回答 4

3

我想,你实际上想要做的应该是这样的:

SELECT COALESCE((
    SELECT now() - min(AcctStartTime)
    FROM   radacct
    WHERE  userName = 'test156'), interval '0s')

如果子选择(带有别名elapsed_time_from_first_login)没有找到行,它将返回一个 NULL 值,但没有行

要抓住这一点,您可以将其包装whole sub-select在一个COALESCE语句中 - 这比CASE目的更简单。

min()起初我忽略了将“无行”转换为NULL. 因此,只要您在子选择中有一个聚合函数,下面的简单表单也可以解决问题。这是一个关于 sqlfiddle 的快速演示,以显示效果

已经指出了您查询的其他问题。但这是更简单的解决方案。它返回一个interval而不是一个integer


转换为整数

在@artaxerxe 评论后简化。
简单的表格可以在不检查“无行”的情况下完成这项工作:

SELECT COALESCE(EXTRACT(epoch FROM now() - min(AcctStartTime))::int, 0)
FROM   radacct
WHERE  userName = 'test156';

EXTRACT(epoch FROM INTERVAL) 手册中有关的详细信息。

聚合函数和 NULL

还有一点:如果你使用了聚合函数count()——而不是sum()你最初在问题中使用的函数——结果会有所不同。count()是标准聚合函数中的一个特例,它从不返回NULL. 如果没有找到值(或行),则返回0

聚合函数手册的摘录似乎涵盖了很多内容:

需要注意的是,除了count之外,这些函数在没有选择行时返回一个空值。特别是,没有行的总和返回 null,而不是预期的零,并且当没有输入行时,array_agg 返回 null 而不是空数组。必要时,可使用 coalesce 函数将零或空数组替换为 null。

于 2012-08-09T07:52:51.763 回答
2

0Postgres抱怨这elapsed_time_from_first_login不是同一类型。

试试这个(也简化你的选择):

select
    coalesce(elapsed_time_from_first_login::INT4, 0)
from ...
于 2012-08-09T07:06:38.053 回答
1

这是我格式化的方式SQL,现在正在工作:

选择合并(结果,0)
     FROM (SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) 结果
                FROM radacct WHERE UserName = 'test156') as elapsed_time_from_first_login;
于 2012-08-09T07:12:56.793 回答
1

第二个SELECT是返回一个表,以elapsed_time_from_first_login一列一行命名。您必须为该列起别名并在CASE子句中使用它。您不能将整个表(即使它是一列,仅一行)放在预期值的位置。

SELECT (CASE (elapsed_time IS NULL) 
                        WHEN true THEN 0 
                        ELSE elapsed_time end) 
   FROM (SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) 
                AS elapsed_time                -- column alias
         FROM radacct 
         WHERE UserName = 'test156'
        ) as elapsed_time_from_first_login;    -- table alias

CASE并且您可以通过使用该函数来缩短COALESCE()(并且可以选择为该列添加一个别名以显示在结果中):

SELECT COALESCE(elapsed_time, 0) 
         AS elapsed_time 
   FROM (SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) 
                AS elapsed_time            
         FROM radacct 
         WHERE UserName = 'test156'
        ) as elapsed_time_from_first_login;    -- table alias
于 2012-08-09T07:38:28.140 回答