2008-10-02 64 views
20

我必须编写一个在Oracle数据库中重新创建SQL Server表(结构和数据)的组件。该组件还必须将新数据输入Oracle数据库并将其复制回SQL Server。Oracle认为空字符串为空,而SQL Server不空 - 这是如何最好地处理?

将数据类型从SQL Server转换为Oracle不是问题。但是,Oracle和SQL Server之间的一个关键差异正在引起很大的头痛。 SQL Server认为空值字符串(“”)与NULL值不同,因此char列可以定义为NOT NULL,但数据中仍包含空白字符串。如果列定义为NOT NULL,则不能插入空白字符串。每当NOT NULL字符列在原始SQL Server数据中包含空白字符串时,就会导致组件中断。

到目前为止,我的解决方案是在我的任何镜像Oracle表定义中不使用NOT NULL,但我需要一个更强大的解决方案。这必须是一个代码解决方案,所以答案不能“使用某某的SQL2Oracle产品”。

你会如何解决这个问题?

编辑:这是我迄今为止唯一提出的解决方案,它可能有助于说明问题。因为Oracle不允许NOT NULL列中的“”,所以我的组件可以拦截来自SQL Server的任何此类值,并将其替换为“@”(仅举个例子)。

当我向Oracle表添加一条新记录时,如果我真的想插入一个“”,我的代码必须写“@”,并且当我的代码将新行复制回SQL Server时,它必须拦截“@”代替写“”。

我希望有一个更优雅的方式。

编辑2:有没有可能有一个更简单的解决方案,就像Oracle中的一些设置可以使它与所有其他主要数据库一样处理空白字符串?此设置是否也可在Oracle Lite中使用?

+0

关于您的编辑2:有一个可怕的解决方案,包括对所有这些列使用CLOB。 Oracle区分NULL和一个空的CLOB。您可以将CLOB内联存储在表中以降低性能影响。我不会这样做(请参阅下面的实际答案)。 – 2011-10-25 06:29:01

+0

@WW .:你是完全正确的 - 这是一个可怕的解决方案。 – MusiGenesis 2011-10-25 13:25:18

+1

圣牛。 SQL Server有它自己的愚蠢分享,但这纯粹是无稽之谈。 (这是否仍然是当前的2014+ Oracle,并且已经为它添加了“ANSI NULL”设置?SQL Server有一些像这样的“ANSI NULL”处理问题。) – user2864740 2015-01-27 16:11:18

回答

10

我看不到一个简单的解决方案。

也许你可以将你的值存储为一个或多个空格-> ' ',它们不是Oracle中的NULLS,或者通过额外的字段/表格和适配器层跟踪这个特殊情况。

3

您是否必须允许SQL Server系统中的空字符串?如果您可以向不允许空字符串的SQL Server系统添加约束,那可能是最简单的解决方案。

1

如果要迁移数据,您可能必须用空格替换空字符串。不是很优雅,但可行。这是Oracle的一个令人讨厌的“特征”。

9

我典型的解决办法是在SQL Server中添加约束迫使受影响的列中的所有字符串值的长度大于0:

CREATE TABLE Example (StringColumn VARCHAR(10) NOT NULL) 

ALTER TABLE Example 
ADD CONSTRAINT CK_Example_StringColumn CHECK (LEN(StringColumn) > 0) 

然而,正如你所说,你无法控制通过SQL数据库。因此,你真的有四种选择(在我看来):

  1. 款待空字符串值无效,跳过那些记录,提醒操作员,并以某种方式,可以方便进行手动校正/重日志记录-输入。
  2. 将空字符串值转换为空格。
  3. 将空字符串值转换为代码(即“LEGACY”或“EMPTY”)。
  4. 在这些列中遇到空字符串值的回滚传输,然后向SQL Server数据库所有者施加压力以更正其数据。

数字四将是我的偏好,但并不总是可能的。你采取的行动将取决于oracle用户需要什么。最终,如果没有关于SQL数据库的事情,我会向Oracle业务系统所有者说明问题,解释选项和后果,并让他们做出决定:)

注意:我相信这种情况SQL Server实际上表现出“正确”的行为。

3

它的讨厌,可能会有意想不到的副作用..但你可以插入“chr(0)”而不是“'。

drop table x 

drop table x succeeded. 
create table x (id number, my_varchar varchar2(10)) 

create table succeeded. 
insert into x values (1, chr(0)) 

1 rows inserted 
insert into x values (2, null) 

1 rows inserted 
select id,length(my_varchar) from x 

ID      LENGTH(MY_VARCHAR)  
---------------------- ---------------------- 
1      1      
2            

2 rows selected 

select * from x where my_varchar is not null 

ID      MY_VARCHAR 
---------------------- ---------- 
1      
3

NOT NULL是一种数据库约束,用于停止将无效数据放入数据库。这在Oracle数据库中没有任何用处,所以我不会拥有它。

我想你应该继续允许任何Oracle列中的NULLS镜像已知包含空字符串的SqlServer列。

如果SqlServer数据库在NULL和空字符串之间存在逻辑差异,那么您需要额外的东西来模拟Oracle中的这种差异。

2

对于那些认为空字符串和空字符串应该被认为是相同的。 null与空字符串具有不同的含义。它捕捉了'未定义'和'已知为空'之间的区别。作为一个例子,记录可能已经被自动创建,但从未被用户输入验证,并且因此在用户验证它时预期会收到'空',其将被设置为空。实际上,我们可能不希望在空值上触发逻辑,但可能需要空字符串。这与“Yes/No/Undefined”的3状态复选框类似。

SQL和Oracle都没有完全正确。空白不应该满足'非空'约束,并且需要对空字符串进行不同的处理,而不是对空值进行处理。

0

我写了一篇关于Oracle如何在我的博客上处理空值的解释。点击这里查看:http://www.psinke.nl/blog/hello-world/如果您还有其他问题,请告诉我。 如果从空值的源有数据,你必须转换到列NOT NULL Oracle数据库中,有两件事情可以做:

  • 从Oracle列中删除NOT NULL约束
  • 检查每个列是否可以在列中放置“'或0或假日期以便能够保存数据。
0

那么,我会考虑的主要观点是当某些字段可以为空时,同一个字段可以为空的字符串和业务逻辑需要区分这些值时缺少任务。所以我会做这样的逻辑:

  • 检查MSSQL如果列有NOT NULL约束
  • 检查MSSQL如果列有CHECK(列<> '')或类似的约束

如果两者都是的,使Oracle列NOT NULL。如果任何一个为真,则使Oracle列为NULL。如果没有,则引发INVALID DESIGN异常(或者可以忽略它,如果这个应用程序可以接受的话)。

将数据从MSSQL发送到Oracle时,只要不做任何特殊处理,所有数据都会正确传输。将数据检索到MSSQL时,应该按原样发送任何非空数据。对于空字符串,您应该决定是将它插入为空还是空字符串。要做到这一点,你应该再次检查表格设计(或记住以前的结果),看看它是否有NOT NULL约束。如果有 - 使用空字符串,如果没有 - 使用NULL。简单而聪明。

有时,如果您使用未知且不可预知的应用程序,则无法检查是否存在{not empty string}约束,因为它有各种形式。如果是这样,您可以使用简化逻辑(使Oracle列始终为空)或检查是否可以将空字符串无差错地插入到MSSQL表中。

2

我会在oracle端添加一列。让你的列允许空值,并有第二列标识SQL-Server端是否应为该行获取空值或空字符串。

0

虽然,在大多数情况下,我同意大多数其他答复的(不会进入任何一个论点我不同意 - 不为:)的地方)

我注意到,OP提到以下内容:

“Oracle认为空白字符串与NULL值相同,因此如果char列被定义为NOT NULL,则不能插入空白字符串。”

具体调用CHAR而不是VARCHAR2。 因此,谈论长度为0(即'')的“空字符串”是没有意义的。 如果他将CHAR声明为CHAR(5),那么只需为将要填入的空字符串添加一个空格,无论如何甲骨文将会填充它。您将以5个空格字符串结束。

现在,如果OP意味着VARCHAR2,那么是的,这是一个完整的其他野兽,是的,空字符串和NULL之间的区别变得相关。

SQL> drop table junk; 

    Table dropped. 

    SQL> 
    SQL> create table junk (c1  char(5) not null); 

    Table created. 

    SQL> 
    SQL> insert into junk values ('hi'); 

    1 row created. 

    SQL> 
    SQL> insert into junk values (' '); 

    1 row created. 

    SQL> 
    SQL> insert into junk values (''); 
    insert into junk values ('') 
          * 
    ERROR at line 1: 
    ORA-01400: cannot insert NULL into ("GREGS"."JUNK"."C1") 


    SQL> 
    SQL> insert into junk values (rpad('', 5, ' ')); 
    insert into junk values (rpad('', 5, ' ')) 
          * 
    ERROR at line 1: 
    ORA-01400: cannot insert NULL into ("GREGS"."JUNK"."C1") 


    SQL> 
    SQL> declare 
    2 lv_in varchar2(5) := ''; 
    3 begin 
    4  insert into junk values (rpad(lv_in||' ', 5)); 
    5 end; 
    6/

    PL/SQL procedure successfully completed. 

    SQL>