这是我的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()函数)。< / p>
问题:您对如何处理此查询有什么建议吗?
答案 0 :(得分:3)
我想,你实际上要做的事情应该是这样的:
SELECT COALESCE((
SELECT now() - min(AcctStartTime)
FROM radacct
WHERE userName = 'test156'), interval '0s')
如果子选择(别名 < / p> <击>
elapsed_time_from_first_login
)没有找到行,它将返回NULL值,但没有行。
要抓住这个,你可以将 whole sub-select
包装在COALESCE
语句中 - 这比CASE
更简单。
我首先忽略了汇总函数min()
,它将“无行”转换为NULL
。因此,只要您在子选择中有一个聚合函数,下面的简单形式就可以了。这是一个快速demo on sqlfiddle to show the effect。
已经指出了查询的其他问题。但这是更简单的解决方案。它会返回interval
而不是integer
。
在@artaxerxe评论之后简化。
简单的表单无需检查“无行”即可完成工作:
SELECT COALESCE(EXTRACT(epoch FROM now() - min(AcctStartTime))::int, 0)
FROM radacct
WHERE userName = 'test156';
有关EXTRACT(epoch FROM INTERVAL)
in the manual。
还有一句话:如果您使用了最初在问题中使用的汇总函数count()
- 而不是sum()
- 结果会有所不同。 count()
是标准聚合函数中的一个特例,因为它永远不会返回NULL
。如果未找到任何值(或行),则返回0
。
这excerpt from the manual on aggregate functions似乎涵盖了它:
应该注意除了count之外,这些函数返回a 没有选择行时为null。特别是,没有行的总和 返回null,而不是正如人们所期望的那样,并且array_agg返回null 没有输入行时,而不是空数组。合并 function可用于将零或空数组替换为null 必要时。
答案 1 :(得分:2)
Postgres抱怨0
和elapsed_time_from_first_login
的类型不同。
试试这个(也简化你的选择):
select
coalesce(elapsed_time_from_first_login::INT4, 0)
from ...
答案 2 :(得分:1)
以下是我格式化SQL
的方法,现在正在运行:
SELECT coalesce(result, 0) FROM (SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) as result FROM radacct WHERE UserName = 'test156') as elapsed_time_from_first_login;
答案 3 :(得分: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