2017-07-18 39 views
2

我有2种模式/如图所示表:有什么方法可以引用具有不同数据类型的列?

CREATE TABLE schema1.code_tbl 
(code  CHAR(6) PRIMARY KEY, 
    description CHAR(30) 
); 

CREATE TABLE schema2.record_tbl 
(rec_id VARCHAR(10) PRIMARY KEY, 
    curr_code VARCHAR(6), 
    remarks VARCHAR(30) 
); 

我需要CODE_TBL创建从curr_codeRECORD_TBLcode的外键引用。

ALTER TABLE schema2.record_tbl 
ADD CONSTRAINT record_code_fk 
FOREIGN KEY (curr_code) 
REFERENCES schema1.code_tbl (code); 

这显然给了我一个ORA-02267(列类型与引用的列不兼容)错误。

我无法更改CODE_TBL中的代码列,因为我没有拥有或控制schema1。我无法更改RECORD_TBL中的curr_code列,因为它会破坏我应用程序中的许多功能,因为我们不考虑尾随空格。

是否有任何其他方式来强制执行2列之间的参照完整性?

回答

2

如果SCHEMA2上的Oracle 11g及以上,使用虚拟列可以解决你的问题,但是这会改变你的表,你正试图避免的结构。如果你能管理它,在这里是如何可以做到

SQL> CREATE TABLE code_tbl 
    2 (code  CHAR(6) PRIMARY KEY, 
    3 description CHAR(30) 
    4 ); 
Table created 

SQL> 
SQL> CREATE TABLE record_tbl 
    2 (rec_id VARCHAR2(10) PRIMARY KEY, 
    3 curr_code VARCHAR2(6), 
    4 remarks VARCHAR2(30) 
    5 ); 
Table created 

SQL> INSERT INTO code_tbl(code, description) VALUES ('ABC', 'Test Data'); 
1 row inserted 

SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('1', 'ABC', 'Test Row'); 
1 row inserted 

SQL> SELECT * FROM record_tbl; 
REC_ID  CURR_CODE REMARKS 
---------- --------- ------------------------------ 
1   ABC  Test Row 

SQL> SELECT * FROM code_tbl; 
CODE DESCRIPTION 
------ ------------------------------ 
ABC Test Data 

SQL> ALTER TABLE record_tbl ADD curr_code_v CHAR(6) AS (trim(curr_code)); 
Table altered 

SQL> SELECT * FROM record_tbl; 
REC_ID  CURR_CODE REMARKS      CURR_CODE_V 
---------- --------- ------------------------------ ----------- 
1   ABC  Test Row      ABC 

SQL> 
SQL> ALTER TABLE record_tbl 
    2 ADD CONSTRAINT record_code_fk 
    3 FOREIGN KEY (curr_code_v) 
    4 REFERENCES code_tbl (CODE); 
Table altered 

SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('2', 'ABC', 'Test Row 2'); 
1 row inserted 

SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('3', 'XYZ', 'Test Row 2'); 
INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('3', 'XYZ', 'Test Row 2') 
ORA-02291: integrity constraint (USER_X.RECORD_CODE_FK) violated - parent key not found 

以下是汤姆凯特关于虚拟列的话: https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:676611400346196844

+0

谢谢你的回答。我已经在我的本地设置上进行了测试,效果很好。虽然我的老板和DBA会批准这样的措施(改变生产中的表格结构总是有点棘手),但我仍然可以肯定地说,从技术上讲这是一个可行的解决方案。 – sml485

0

您不能在不同类型的列中创建关系。 为什么你必须在数据库中创建关系?您只能使用代码连接表格。

+1

历史的教训是对付你。在应用程序中执行关系完整性而不是数据库不可避免地导致数据损坏。 – APC

2

所以情况是这样的。你有一个现有的表record_tbl这是很好的(显然,因为改变它“打破许多职能”)。迟来有人决定在该表上强制执行关系完整性,但选择在不同数据类型的列中引用不同架构中的表。

嗯。

的选项有:

  1. 什么也不做。总是一个选择;您的应用程序在当前状态下存活了一段时间,也许您可​​以继续接受应计技术债务。
  2. 重构其中一个模式。如果你需要执行外键 - 让我们面对它,关系完整性是一件好事 - 那么你将不得不改变其中一列的数据类型。你选择哪一个是一个项目决策:改变你不拥有的模式中的列是一个政治问题(最初),政治问题通常比技术问题更难。通过更改列类型来重构模式是测试,测试和测试的问题。
  3. 复制。在schema2中构建实体化视图,该视图从schema1.code_tbl复制数据。最重要的是,定义MView code列匹配schema2.record_tbl.curr_code的数据类型,即varchar2(6)。您现在可以对schema2.mv_code_tbl.code执行外键。 注意: MView列中的数据将被格式化为CHAR,即具有尾随空格。
+0

谢谢你的建议。不幸的是,这是我正在使用的遗留系统。我不确定为什么我的前任这样设计它。 Schema2过去有自己可以引用的'code_tbl'的副本,但由于我未知的原因(可能保留2个代码表太过繁重)而被删除。外键考虑显然没有提出,因为当我接手这个系统时没有任何东西。 – sml485

相关问题