用 Oracle 来说,这将是一个
NUMBER(9, 0)
或任何映射到 32 位(甚至 16 位或 64 位)整数的内容。
CREATE TABLE T(C1 NUMBER, C2 NUMBER(9, 0) ); -- Unconstrained and constrained number
INSERT INTO T(C1, C2) VALUES (10, 10);
SELECT C1, C2 FROM T; -- C1 is NUMBER, C2 is NUMBER(9,0)
Oracle 假定了精度和小数位数,然后似乎没有办法在不修改表结构本身的情况下设置它们:
SELECT
CAST(C1 AS INTEGER) FAILURE1, -- Unconstrained number
TRUNC(C1) FAILURE2, -- Unconstrained number
ROUND(C1, 0) FAILURE3, -- Unconstrained number
CAST(ROUND(C1, 0) AS NUMBER(9, 0)) FAILURE4, -- Unconstrained number
TO_NUMBER(TO_CHAR(PERCENT_DONE, '99') FAILURE5, -- ~Overcomplicated and still fails
FROM T
这使得编写与 Oracle 一起使用的应用程序变得更加困难,并且还使它们变得更慢且内存效率更低。像 Stack Overflow 自己的 Dapper 这样的 ORM 及其底层驱动程序不知道不受约束的数字可能包含什么,因此它们将这些列映射到类型,例如
System.Decimal
,而不仅仅是简单的整数类型。
Oracle 确实有
TO_BINARY_FLOAT()
和 TO_BINARY_DOUBLE()
分别映射到 float 和 double,但是如何用整数来完成呢?
NUMBER
数据类型的存储在 Oracle 中,
NUMBER
是一种精确的数字数据类型,指数用 1 个字节表示,数字的每两位数字用 1 个字节表示。
如果对于您的示例数据,您使用:
SELECT DUMP(C1), DUMP(CAST(C1 AS NUMBER(9,0))), DUMP(C2) FROM T;
然后您将看到查询返回的二进制值:
转储(C1) | 转储(CAST(C1ASNUMBER(9,0))) | 转储(C2) |
---|---|---|
典型=2 长度=2:193,11 | 典型=2 长度=2:193,11 | 典型=2 长度=2:193,11 |
如您所见,数据库不会传递有关基础列数据类型的数据和值,它仅传递值(并且使用
CAST
不会更改值)。
即使基础列是
NUMBER
或 NUMBER(9,0)
,数据库也仅传递 2 字节信息,在这种情况下,比使用 32 位(4 字节)或 64 位更有效(8 字节)整数。
Oracle 具有 数据类型:
NUMBER(p, s)
- 存储精确值,范围从 -84 到 +127,精度为 1 到 38 位十进制数字。
NUMERIC
和 DECIMAL
- 是 NUMBER
FLOAT(p)
- NUMBER
的子类型,精度为 1 到 126 个二进制数字(即 NUMBER(1)
到 NUMBER(38)
)。 FLOAT
和 DOUBLE PRECISION
是 FLOAT(126)
的别名,REAL
是 FLOAT(63)
的别名。INTEGER
、INT
和 SMALLINT
- 是 NUMBER(38)
BINARY_DOUBLE
- 64 位浮点数。BINARY_FLOAT
- 32 位浮点数。Oracle 确实有 TO_BINARY_FLOAT() 和 TO_BINARY_DOUBLE() 分别映射到 float 和 double,但是如何用整数来完成此操作?
Oracle SQL 中没有
BINARY_INTEGER
数据类型(它存在于 PL/SQL 中)。 Oracle 中不存在您所要求的内容;只有 NUMBER
、BINARY_FLOAT
或 BINARY_DOUBLE
。
但是,您所要求的与Oracle数据库的内部无关;相反,它与与数据库通信的数据库驱动程序如何将值返回给第三方编程语言有关。
例如,.NET 数据提供程序开发人员指南文档中有一个关于“将 Oracle 数据类型映射到 EDM 类型”的部分:
表 4-1 Oracle 数据类型和 EDM 类型的映射
Oracle 数据类型二进制_双精度二进制_浮点数二进制_整数浮动国际数字(1,0)数字(2,0)数字(6,0)数字(7,0)数字(11,0)数字(12,0)数量(所有其他情况)小林特这表明,对于那个司机来说,你想要的已经完成了。
EDM 类型(Primitive-TypeKind) 双 单人 Int32 十进制 Int32 数字(3,0)
数字(4,0)
数字(5,0)
Int16数字(8,0)
数字(9,0)
数字(10,0)
Int32数字(13,0)
数字(14,0)
数字(15,0)
数字(16,0)
数字(17,0)
数字(18,0)
数字(19,0)
Int64十进制 Int16
在甲骨文中:
CREATE TABLE my_schema.T(c1 NUMBER(9,0) NOT NULL, c2 NUMBER NOT NULL)
以下完整的 C# 控制台应用程序可以粘贴到新项目的 Program.cs 上进行演示:
using System.Data;
using Oracle.ManagedDataAccess.Client;
// Normally you want to use Dapper or EF and not the raw driver calls.
// The presence of the SQL and cstr in this file are for demonstration purposes only.
var connection = new OracleConnection();
connection.ConnectionString = "SOME CONNECTION STRING";
using var cmd = new OracleCommand();
cmd.CommandText = """
SELECT
c1,
c2,
CAST(C1 AS INTEGER) i1,
CAST(C2 AS INTEGER) i2,
TRUNC(C1) t1,
TRUNC(C2) t2,
ROUND(C1, 0) r1,
ROUND(C2, 0) r2,
CAST(ROUND(C1, 0) AS NUMBER(9, 0)) rc1,
CAST(ROUND(C2, 0) AS NUMBER(9, 0)) rc2,
CAST(C1 AS NUMBER(18, 0)) rc1,
CAST(C2 AS NUMBER(18, 0)) rc2
FROM my_schema.T
""";
cmd.Connection = connection;
connection.Open();
using IDataReader reader = cmd.ExecuteReader();
while(reader.Read()) {
for(var columnCount = 0; columnCount < reader.FieldCount; columnCount++) {
Type type = reader.GetFieldType(columnCount);
var val = reader.GetValue(columnCount);
var fieldName = reader.GetName(columnCount);
Console.WriteLine($"{fieldName}:{val}:{type}");
}
}
这产生:
C1:100:System.Int32
C2:100:System.Decimal <-- Want C2 as a NUMBER(9,0) or similar
I1:100:System.Decimal
I2:100:System.Decimal
T1:100:System.Decimal
T2:100:System.Decimal
R1:100:System.Decimal
R2:100:System.Decimal
RC1:100:System.Int32 <-- ✅
RC2:100:System.Int32 <-- ✅
RC1:100:System.Int64 <-- ✅
RC2:100:System.Int64 <-- ✅
最后四行 Int32 和 Int64 是我所需要的。 小数 = 不好,除非我们确实需要 128 位结构类型来存储值。
CAST()
更改传出数据类型
。 我原来的帖子显示这返回了一个不受约束的数字,但显然,我错了。我最初的测试有一个 ROUND 包裹着 CAST,我没想到会删除有关精度和比例的所有信息。