我们正在测试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:
非常感谢任何帮助。谢谢。
答案 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';