我有一个SQL程序,它在每一行中递增,并在值上填充一些尾随零,具体取决于小数点后的值的长度。试图将其转移到PSQL环境中我意识到SQL和PSQL之间存在很多语法差异。我设法随着时间的推移进行转换,但我仍然遇到语法错误,无法弄清楚原因。有人可以帮我弄清楚为什么这不会运行?我目前在PGadmin中运行它,如果这有任何区别。
DO $$
DECLARE
counter integer;
before decimal;
after decimal;
BEGIN
counter := 1;
WHILE counter <> 2 LOOP
before = (select code from table where ID = counter);
after = (SELECT SUBSTRING(code, CHARINDEX('.', code) + 1, LEN(code)) as Afterward from table where ID = counter);
IF before = after
THEN
update table set code = before + '.0000' where ID = counter;
ELSE
IF length(after) = 1 THEN
update table set code = before + '000' where ID = counter;
ELSE IF length(after) = 2 THEN
update table set code = before + '00' where ID = counter;
ELSE IF length(after) = 3 THEN
update table set code = before + '0' where ID = counter;
ELSE
select before;
END IF;
END IF;
counter := counter + 1;
END LOOP
END $$;
预期结果的输入/输出的一些示例:
Input 55.5 > Output 55.5000
Input 55 > Output 55.0000
感谢您的帮助, 贾斯汀
答案 0 :(得分:0)
当显示时,表格上不需要函数甚至更新来格式化值。
假设这些值实际上是存储在decimal
或float
列中的数字,您需要做的就是在检索时应用to_char()
函数:
select to_char(code, 'FM999999990.0000')
from data;
这将输出55.5000或55.0000
to_char()
函数的缺点是您需要预测可能发生的最大位数。如果格式掩码中的9
不够,则输出将类似于#.###
。但由于格式掩码中的数字太多而没有受到伤害,我通常会在格式掩码中投入很多。
有关格式化功能的详细信息,请参阅手册:
https://www.postgresql.org/docs/current/static/functions-formatting.html#FUNCTIONS-FORMATTING-NUMERIC-TABLE
如果您坚持存储格式化数据,可以使用to_char()
更新表格:
update the_table
set code = to_char(code::numeric, 'FM999999990.0000');
如果列中存在非数字值,则将值转换为数字当然会失败。
但同样:我强烈建议将数字存储为数字,而不是字符串。
如果要将其与用户输入进行比较,最好将用户输入转换为正确的数字,并将 与存储在数据库中的(数字)值进行比较。
您所追求的字符串匹配实际上并不需要函数。将substring()
与正则表达式一起使用即可:
update the_table
set code = code || case length(coalesce(substring(code from '\.[0-9]*$'), ''))
when 4 then '0'
when 3 then '00'
when 2 then '000'
when 1 then '0000'
when 0 then '.0000'
else ''
end
where length(coalesce(substring(code from '\.[0-9]*$'), '')) < 5;
substring(code from '\.[0-9]*$')
提取.
后面跟着字符串末尾的数字的所有内容。因此,对于55.0
,它会为.0
返回55.50
,如果值中没有.50
,则返回.
,然后返回null
这就是为什么需要合并。
该子字符串的长度告诉我们存在多少位数。根据我们的不同,我们可以附加必要数量的零。可以缩短case
,以便不必列出所有可能的长度(但这并不简单):
update the_table
set code = code || case length(coalesce(substring(code from '\.[0-9]*$'), ''))
when 0 then '.0000'
else lpad('0', 5- length(coalesce(substring(code from '\.[0-9]*$'), '')), '0')
end
where length(coalesce(substring(code from '\.[0-9]*$'), '')) < 5;
另一种选择是使用字符串中.
的位置来计算需要添加的0
的数量:
update the_table
set code =
code || case
when strpos(code, '.') = 0 then '0000'
else rpad('0', 4 - (length(code) - strpos(code, '.')), '0')
end
where length(code) - strpos(code, '.') < 4;
正则表达式相当昂贵,不使用它们会使速度更快。但是,只有在值中最多只有一个.
时,上述内容才有效。
但是,如果您可以确定每个值都可以转换为数字,那么带有强制转换的to_char()
方法肯定是最强大的。
要仅处理code
列包含正确数字的行,可以在SQL语句中使用where子句:
where code ~ '^[0-9]+(\.[0-9][0-9]?)?$'
答案 1 :(得分:0)
要将列类型更改为数字:
alter table t alter column code type numeric