postgresql - 将行值与文本字段与 CASE 中的无类型字符串文字行进行比较
问题描述
我在 stackoverflow 上找到了一种使用 ROW 值处理多变量case
语句的巧妙方法。它看起来多么干净真是太棒了......
但是,直接将由 2 个类型的表列组成的行值text
与由字符串文字组成的行进行比较时,我会遇到错误。
我已经使用了一种解决方法,该功能spTup('Deposit', '' )
可以使用但可能会更慢。另一种可行的方法是将字符串文字显式转换为text
,但这会产生很多视觉混乱。
问题:
- 为什么 Postgres 不能推断字符串文字应该被视为
text
类型? - 为什么 Postgres 可以在单个元素行中推断字符串文字的类型,而不是具有 2 个元素的行?
- 我以为我正在处理 Postgres 类型处理,但我不太明白这种情况,谁能解释一下?
- 有没有其他方法可以最大限度地减少视觉混乱?
我在本地主机上使用 Postgres 10.1,在测试和生产服务器上使用 9.6.6。
测试设置:
create table if not exists tblTest ( SeqID serial, EventType text, EventResult text, Amt decimal );
truncate table tblTest;
insert into tblTest( EventType, EventResult, Amt )
values ( 'Withdrawal', '', 1.11 ), ('Deposit', '', 2.22 ), ('Deposit', 'succeeded', 3.33 ), ('Deposit', 'failed', 4.44 );
create or replace function spTup( p_1 text, p_2 text )
returns record as $func$
select ( p_1, p_2 );
$func$ LANGUAGE sql IMMUTABLE;
-- Runs without error (using single element tuple)
select SeqID, EventType, case ( EventType ) when ( 'Deposit' ) then Amt else 9.999 end
from tblTest;
-- ERROR: cannot compare dissimilar column types text and unknown at record column 1
select SeqID, EventType, EventResult, case ( EventType, EventResult )
when ( 'Deposit', '' ) then Amt else 9.999 end
from tblTest;
-- Runs without error -- visually the cleanest apart from using spTup function
select SeqID, EventType, EventResult, case ( EventType, EventResult )::text
when ( 'Deposit', '' )::text then Amt else 9.999 end
from tblTest;
-- Runs without error
select SeqID, EventType, EventResult, case ( EventType, EventResult )
when ( 'Deposit'::text, ''::text ) then Amt else 9.999 end
from tblTest;
select SeqID, EventType, EventResult, case ( EventType, EventResult )
when spTup( 'Deposit', '' ) then Amt else 9.999 end
from tblTest;
-- ERROR: input of anonymous composite types is not implemented
select SeqID, EventType, EventResult, case ( EventType, EventResult )
when '( "Deposit", "" )' then Amt else 9.999 end
from tblTest;
-- Just out of interest
select ( 'Deposit', '' ), ( 'Deposit'::text, ''::text );
/**
row row
(Deposit,"") (Deposit,"")
**/
select SeqID, EventType, EventResult, ( EventType, EventResult )
from tblTest;
/**
seqid eventtype eventresult row
1 Withdrawal (Withdrawal,"")
2 Deposit (Deposit,"")
3 Deposit succeeded (Deposit,succeeded)
4 Deposit failed (Deposit,failed)
**/
解决方案
这似乎是对您正在使用的“简单”或“切换”的限制。CASE
没有显式转换的作品
的替代语法变体:CASE
select SeqID, EventType, EventResult
, CASE WHEN (EventType, EventResult) = ('Deposit', '') THEN amt ELSE 9.999 END
from tblTest;
只要您有一个案例要测试,这个变体甚至可以“最大限度地减少视觉混乱”。两个额外的字符,但更容易阅读(恕我直言)。不过,对于多种情况,“切换”变体似乎更可取。
不同的行为显然是由“简单”中不同的工作流程引起的CASE
。手册:
第一个
expression
被计算,然后与子句value
中的每个表达式进行比较,WHEN
直到找到一个等于它的表达式。
简单表达式-值比较的代码路径尝试较少地解析数据类型-并且对于匿名行值失败。感觉是实施中的一个缺点。人们可能期望两种变体具有相同的行为 - 并提交错误报告。
但至少从 Postgres 8.4 开始,这种行为就一直是这样的(在 pg 11 中也是如此):
db<>在这里摆弄
CASE
到目前为止,可能很少有人对未键入的行值有类似的想法。
留下你的问题:
- 为什么 Postgres 可以在单个元素行中推断字符串文字的类型,而不是具有 2 个元素的行?
回答:因为在 Postgres 中几乎所有地方都对表达式求值时,具有单个元素 ( (foo)
) 的行值被简化为它们的单个元素 ( )。foo
所以这:
CASE (eventtype) WHEN ('Deposit') THEN ...
有效地简化为:
CASE eventtype WHEN 'Deposit' THEN ...
推荐阅读
- r - 使用 R 中的 ggplot2 对堆积区域图进行图案填充
- javascript - 如何在 Vue JS 应用启动时加载配置
- javascript - 回复:无法居中 div 部分
- javascript - 如何在下拉容器中使用过渡,使其缓慢显示,直到达到我想要的大小?
- python - Python:没有名为“gym”的模块
- javascript - 唯一标识单击按钮的表行
- typescript - 如何为 Chrome 扩展配置 tsconfig.json 以便我可以创建模块
- javascript - JavaScript回调函数在运行时不保留参数?
- c# - 如何加密 cookie 以使令牌不可读
- c# - 如何从实体框架中的(任何)表中记录读取