oracle 是否有一个VARCHAR2的范围可以在SQL中自动转换为NUMBER?

s8vozzvw  于 2023-10-16  发布在  Oracle
关注(0)|答案(2)|浏览(107)

下面是一个 *plsql * 游标。

CURSOR get_customer_balance(cust_id_ IN VARCHAR2) IS
      SELECT t.cust_balance
      FROM customer_tab t
      WHERE t.customer_id =cust_id_;

程序机构

OPEN  get_customer_balance(123456789);
FETCH get_customer_balance INTO balance_;
CLOSE get_customer_balance;
  • 在customer_tab中,customer_id是一个数字类型列。即使游标参数是varchar2,也可以正常工作。对于某些值,这给予误差。此外,任何错误都将仅在运行时发生。*

是否有一个 * 范围的varchar2* 可以自动 * 转换为数字?***

cotxawn7

cotxawn71#

在customer_tab中,customer_idnumber类型列
vs.
CURSOR get_customer_balance(cust_id_ IN VARCHAR2) IS
意思是你故意做错事
不仅如此,你应该传递一个number--事实上,你应该传递customer_tab.customer_id%type,这样游标声明就应该是

CURSOR get_customer_balance(cust_id_ IN customer_tab.customer_id%type) IS

关于你的问题:Oracle将尝试隐式地将您传递的任何数据类型转换为有效数字。有时它会成功(例如,如果你传递'10'),有时不会('ABC''15XF4')。没有“范围”;这取决于实际价值。
如果你愿意,可以看看Tom Kyte的<a=href=”https://blogs.oracle.com/connect/post/on-implicit-conversions-and-more“>关于隐式转换和更多内容,其中包括:
问题出在你的代码上。您的开发人员编写了一个非常讨厌的bug,这个bug被称为“隐式转换”。

cczfrluj

cczfrluj2#

摘要:永远不要依赖数据类型之间的隐式转换。

是否有一个范围的VARCHAR2可以在SQL中自动转换为NUMBER
任何可以从VARCHAR2隐式转换为NUMBERvalue都可以使用TO_NUMBER(value)(使用隐式格式模型)成功显式转换。
一般来说,这将匹配正则表达式:

[+-]?([0-9]+(D[0-9]*)?|D[0-9]+)([eE][+-][0-9]+)?

其中DNLS_NUMERIC_CHARACTERS会话参数指定的十进制分隔符。
还有进一步的限制,因为NUMBER只能存储(大约)38位数字,但你可以转换更大的字符串,它会截断数字超过数字的精度。
例如,给定样本数据:

CREATE TABLE table_name (value) AS
  SELECT '0' FROM DUAL UNION ALL
  SELECT '+00001234' FROM DUAL UNION ALL
  SELECT '-00001234' FROM DUAL UNION ALL
  SELECT '-00001234.' FROM DUAL UNION ALL
  SELECT '-00001234.5678' FROM DUAL UNION ALL
  SELECT '.1234' FROM DUAL UNION ALL
  SELECT '.1234e4' FROM DUAL UNION ALL
  SELECT '.1234E-004' FROM DUAL UNION ALL
  SELECT '1234E-004' FROM DUAL

然后你可以使用CAST函数显式地在数据类型之间执行转换:

SELECT value, CAST(value AS NUMBER) FROM table_name;

其中(当NLS_NUMERIC_CHARACTERS.,时)输出:
| 值|铸件(值编号)|
| --|--|
| 0 | 0 |
| +00001234| 1234 |
| -00001234|-1234|
| -00001234|-1234|
| -00001234.5678 | -1234.5678 |
| .1234|.1234|
| .1234e4| 1234 |
| .1234E-004| 00001234|
| 1234E-004|.1234|
但是,你应该永远依赖于数据类型之间的隐式转换。
如果我们更改会话参数:

ALTER SESSION SET NLS_TERRITORY = 'France';

然后,NLS_NUMERIC_CHARACTERS.,更改为,,并且完全相同的查询和相同的数据:

SELECT value, CAST(value AS NUMBER) FROM table_name;

现在ORA-01722: invalid number失败,因为它现在期望十进制值使用,作为小数点(根据法国和许多其他国家的正常约定)而不是.,现在所有带有.的字符串都无效。
由于任何用户都可以随时更改其会话参数,因此您不能(也不应该)依赖隐式转换始终有效。
如果您想要对任何会话参数都有效的数字,则不能使用小数分隔符,只能使用整数有效数和可选指数:

[+-]?[0-9]+([eE][+-][0-9]+)?

fiddle

相关问题