根据我对该问题的回答,提出了这个问题 Getting weird issue with TO_NUMBER function in Oracle
正如大家都建议将数值存储在VARCHAR2列中并不是一个好习惯(我完全同意),我想知道我们团队的基本设计选择以及是否有更好的设计方法。
问题陈述:我们有许多表格,我们希望提供一定数量的自定义字段。所需的自定义字段数已知,但用户可以使用哪种属性映射到该列
E.g。我在下面假设了一个假设情景
假设您有一台笔记本电脑,可为每条笔记本电脑记录存储50个属性值。每个笔记本电脑属性都是由创建笔记本电脑的管理员创建的。
用户创建的笔记本电脑产品让我们说带有属性字符串,字符串,数字,数字,字符串
的lap1第二位用户使用属性String,numeric,String,String,numeric
创建了laptop2目前我们设计中的数据会保持如下状态
Laptop Table
Id Name field1 field2 field3 field4 field5
1 lap1 lappy lappy 12 13 lappy
2 lap2 lappy2 13 lappy2 lapp2 12
这个例子模拟了我们的要求和我们的设计
现在在这里,如果有人在第2场比赛中查看lap2表的记录,我们需要申请TO_NUMBER。
select * from laptop
where name='lap2'
and TO_NUMBER(field2) < 15
在某些情况下,当查询计划决定首先应用to_number而不是其他过滤器时,TO_NUMBER失败。
问题
这是一个有效的设计吗?
解决这个问题的其他替代方法是什么?
我们的一位队友建议为这些案例动态创建表格。这是个好主意吗?
流行的ORM工具如何提供自定义字段或弹性字段处理?
我希望我能够在这个问题上有意义。
抱歉这么长的文字..
这会导致我们在queryio
时使用TO_NUMBER答案 0 :(得分:4)
这是一个常见问题,并没有完美的解决方案。几个解决方案:
<强> 1 强> 定义varchar2类型的X字段,类型为number的Y字段和date类型的Z字段。这可能是自定义字段数量的3倍,但您将永远不会遇到任何转换问题。
你的例子就是这样的:
Id Name field_char1 field2_char2 field_char3 ... field_num1 field_num2 ...
1 lap1 lappy lappy lappy ... 12 13
2 lap2 lappy2 lappy2 lapp2 ... 13 12
在您的示例中,两行上的数值和字符值都相同,但不一定是这样:例如,第三行可能没有数字字段。
<强> 2 强>
定义varchar2类型的X字段,并将一个双射函数应用于存储数字或日期字段(例如,Date可以存储为YYYYMMDDHH24miss
)。您还需要一个额外的字段来定义行的上下文。只有在行类型良好时才应用to_number
或to_char
函数。
你的例子:
Id Name context field1 field2 field3 field4 field5
1 lap1 type A lappy lappy 12 13 lappy
2 lap2 type B lappy2 13 lappy2 lapp2 12
您可以使用DECODE或CASE查询表:
SELECT *
FROM laptop
WHERE CASE WHEN context = 'TYPE A' THEN to_number(field3) END = 12
第二种设计是Oracle Financials ERP(以及其他)中使用的设计。上下文允许您使用此设计定义CHECK约束(例如CHECK (CASE WHEN context = 'TYPE A' THEN to_number(field3) > 0
)以确保完整性。
答案 1 :(得分:3)
这是收缩包装应用程序的常见场景,它代表了自定义数据模型的唯一机会。但从纯粹主义的角度来看,这是不好的做法。因为如果列可以包含'27 -MAY-2010'或178.50或'Red badger',那么显然它依赖于数据库外部的某些东西来赋予它意义。
但是使用XMLType会更糟糕,因为你失去了你所拥有的小结构。查询灵活列变得困难。仍有一些场景,这是适当的解决方案:主要是当我们对单个元素不感兴趣时,只对属性集合感兴趣。
那么,处理它的最佳方法是什么?自定义功能与自定义列一起使用:
SQL> create or replace function get_number
2 ( p_str in varchar2 )
3 return number
4 deterministic
5 is
6 return_value number;
7 begin
8 begin
9 return_value := to_number(trim(p_str));
10 exception
11 when others then
12 return_value := null;
13 end;
14 return return_value;
15 end;
16 /
Function created.
SQL>
我们可以根据此列构建一个基于函数的函数:
SQL> create index t42_flex_idx on t42 ( get_number( flex_col))
2 /
Index created.
SQL>
所以给出了这个测试数据......
SQL> select * from t42
2 /
ID FLEX_COL
---------- ------------------------------
1 27-MAY-2010
2 138.50
3 Red badger
2 23
SQL>
......这是它的工作原理:
SQL> select * from t42
2 where get_number(flex_col) < 50
3 /
ID FLEX_COL
---------- ------------------------------
2 23
SQL>
答案 2 :(得分:0)
如果在创建表时决定了所有列类型,那么动态生成表对我来说听起来不错。
但是,如果两个用户使用具有不同字段的同一个表,则可以仅为自定义字段创建新表并将它们连接到主表。这更像是一种面向对象的方法。
答案 3 :(得分:0)
您是否可以在代码层中创建XML图并将其存储在SYS.XMLTYPE字段类型中?
http://www.oracle-base.com/articles/9i/XMLTypeDatatype.php
这将允许您强烈键入(在XML中)您的值并保留有意义的结构。