使用函数作为Oracle11g中列的默认值

时间:2011-07-22 20:19:51

标签: sql oracle oracle11g

我们正在测试Oracle的工作,并负责在Oracle上构建所有数据库对象(表,过程,触发器等),我们目前使用的是Microsoft SQL Server 2008 R2。我们几乎为所有ID列使用uniqueidentifier。我用这个函数来创建GUID:

CREATE OR REPLACE FUNCTION NEWID RETURN CHAR IS guid CHAR(36) ;
BEGIN
    SELECT SYS_GUID() INTO guid FROM DUAL;
    guid :=
               SUBSTR(guid,  1, 8) ||
        '-' || SUBSTR(guid,  9, 4) ||
        '-' || SUBSTR(guid, 13, 4) ||
        '-' || SUBSTR(guid, 17, 4) ||
        '-' || SUBSTR(guid, 21);
    RETURN guid;
END NEWID;
/

但是现在我无法弄清楚如何在创建表时将它用作列的默认值。这是一个不起作用的例子:

CREATE TABLE "NonWorkingExample"
(   
  "ID"                              CHAR(36)      NOT NULL DEFAULT   NEWID(),
  "UnitNumber"                      NUMBER(38)    NOT NULL,
  "StartDateTime"                   TIMESTAMP     NOT NULL,
  "EndDateTime"                     TIMESTAMP     NULL,

  CONSTRAINT PK_RentalAgreements  PRIMARY KEY ("ID")
);

错误:

Error starting at line 1 in command:
CREATE TABLE "NonWorkingExample"
(   
  "ID"                          CHAR(36)      NOT NULL DEFAULT NEWID(),
  "UnitNumber"                  NUMBER(38)    NOT NULL,
  "StartDateTime"               TIMESTAMP     NOT NULL,
  "EndDateTime"                 TIMESTAMP     NULL,

  CONSTRAINT PK_RentalAgreements  PRIMARY KEY ("ID")
)
Error at Command Line:3 Column:58
Error report:
SQL Error: ORA-00907: missing right parenthesis
00907. 00000 -  "missing right parenthesis"
*Cause:    
*Action:

非常感谢任何帮助。谢谢。

6 个答案:

答案 0 :(得分:11)

我完全同意其他答案,如果你真的想调用一个函数,你需要使用一个触发器,或者你需要在INSERT语句中嵌入函数调用。在INSERT语句中嵌入函数调用比强制Oracle为您插入的每一行执行触发器更有效。

但是,我应该指出,您可以单独使用SYS_GUID()作为列的默认值,而不必担心触发器

SQL> create table foo (
  2    col1 varchar2(32) default sys_guid(),
  3    col2 number
  4  );

Table created.

SQL> insert into foo( col2 ) values( 1 );

1 row created.

SQL> select * from foo;

COL1                                   COL2
-------------------------------- ----------
7B64E8AE7404421C80A590F65873CD79          1

您真的需要GUID值中的额外破折号吗?您是否可以仅在显示数据时添加破折号?或者,因为您使用11g,添加一个基于函数的虚拟列,将无破折号的GUID转换为您喜欢的格式的GUID?

由于您来自SQL Server,我应该指出,在Oracle中使用序列来填充合成主键而不是使用GUID是常规的。使用序列填充密钥通常比调用SYS_GUID更有效。

答案 1 :(得分:6)

正如@Kerri暗示的那样,您不能将PLSQL函数用作表定义中的默认值。 Oracle documentation中的相关语句是“DEFAFA表达式不能包含对PL / SQL函数的引用......”。

除了作为插入格式化GUID的唯一方法之外,正如您尝试的那样,触发器提供了第二个优势:与默认值不同,触发器设置的值不能被粗心的开发人员覆盖

顺便说一句,你应该真正修改你的newid函数以使用直接赋值而不是select ... from dual

CREATE OR REPLACE FUNCTION NEWID RETURN CHAR IS 
    guid VARCHAR(36);
BEGIN
    guid := SYS_GUID();
    guid :=
               SUBSTR(guid,  1, 8) ||
        '-' || SUBSTR(guid,  9, 4) ||
        '-' || SUBSTR(guid, 13, 4) ||
        '-' || SUBSTR(guid, 17, 4) ||
        '-' || SUBSTR(guid, 21);
    RETURN guid;
END NEWID;
/

最后,我建议您使用varchar2代替char。与popular opinion相反,char没有存储或效率优势,因此您可以将varchar2用于所有内容,只是为了简单起见。

答案 2 :(得分:5)

建议:

  • 改为使用触发器。

例如:

CREATE TRIGGER SetGUIDforTableXYZ BEFORE INSERT ON TableXYZ
FOR EACH ROW
BEGIN
    :new.ID := NEWID();
END;

应该这样做(假设我没有搞砸某处的语法)。

答案 3 :(得分:5)

You can't use a function for this。您没有看到它,因为您的语法错误(在CONSTRAINTS之前为DEFAULT)。你应该:

"ID"    CHAR(36)  DEFAULT NEWID()   NOT NULL ,

此时您将收到以下消息(11g):

SQL> create table tt (id varchar2(36) default newid() not null);
create table tt (id varchar2(36) default newid() not null)
                                   *
ERROR at line 1:
ORA-04044: procedure, function, package, or type is not allowed here


SQL>

正如@Kerri所说,它会触发自动执行此操作。

答案 4 :(得分:0)

如何通过尝试这样的方法来删除函数和触发依赖项:

CREATE TABLE "NonWorkingExample" 
(    
  "ID"                          CHAR(36)      NOT NULL DEFAULT regexp_replace((rawtohex(sys_guid()), '([A-F0-9]{8})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{12})', '\1-\2-\3-\4-\5'), 
  "UnitNumber"                  NUMBER(38)    NOT NULL, 
  "StartDateTime"               TIMESTAMP     NOT NULL, 
  "EndDateTime"                 TIMESTAMP     NULL, 

  CONSTRAINT PK_RentalAgreements  PRIMARY KEY ("ID") 
) 

答案 5 :(得分:0)

如果Oracle SYS_GUID()的某些相似/顺序的GUID困扰您,则可以将java.util.UUID.randomUUID()包装在pl / sql函数中,以减少可预测的值:

CREATE OR REPLACE FUNCTION Java_Util_Random_UUID RETURN VARCHAR2 AS
language java
name 'java.util.UUID.randomUUID() return String';