为什么这个oracle表列接受的数据大于初始大小?

时间:2016-01-16 11:33:15

标签: oracle plsql

我是oracle sql的新手,pl sql.i有写pl sql函数,它以xml格式从php获取数据。这是下面的pl sql代码,它运行正常:

FUNCTION save_overtime(overtime_data NVARCHAR2 ) RETURN clob IS ret clob;
   xmlData XMLType;

   v_code  NUMBER;
   v_errm  VARCHAR2(100);

   BEGIN 
   xmlData:=XMLType(overtime_data);
   INSERT INTO TBL_OVERTIME SELECT x.* FROM XMLTABLE('/overtime'
                                                PASSING xmlData
                                                COLUMNS OT_EMPID   NVARCHAR2(10)     PATH   'employee_id',
                                                        OT_DATE   DATE     PATH    'date',                                                        
                                                        OT_HOUR   NUMBER(4,0)    PATH    'overtime_hour'                                                        
                                                        ) x;


     ret:=to_char(sql%rowcount);
COMMIT;

RETURN '<result><status affectedRow='||ret||'>success</status></result>';
EXCEPTION
WHEN OTHERS THEN
v_code := SQLCODE;
v_errm := SUBSTR(SQLERRM, 1, 100);
DBMS_OUTPUT.PUT_LINE (v_code || ' ' || v_errm);
-- '<result><status>Error</status> <error_message>'|| 'Error Code:' || v_code || ' ' || 'Error Message:' || v_errm ||'</error_message> </result>';
RETURN '<result><status>Error</status> <error_message>'|| 'Error Message:' || v_errm ||'</error_message> </result>';

END save_overtime;

在插入数据时,我注意到oracle表也接受大于其初始大小的数据! 例如,以下列接受大于10的数据。

 EMPID   NVARCHAR2(10) 

如果数据长度为12,则需要前10个字符。但我认为 它应该是无效/错误。因为,否则定义列大小是没有意义的。我知道添加约束。但是为这些小东西添加许多约束是非常无聊和乏味的。如果我做错了/错误,那么请帮助我明白了。谢谢

1 个答案:

答案 0 :(得分:3)

插入不允许并静默截断超过列大小的值。 XMLTable columns子句正在进行截断;其数据类型表示XMLTable投影将返回的内容,并不意味着将根据数据类型大小限制验证指定路径的值。向表中添加约束将没有任何区别。

如果只是从XMLTable表达式查询,而不是插入:

,则可以看到截断
var overtime_data nvarchar2(4000);
exec :overtime_data := '<overtime><employee_id>invalidvalue</employee_id><date>2016-01-15</date><overtime_hour>1234.5</overtime_hour></overtime>';

select x.ot_empid, x.ot_date, x.ot_hour
from xmltable('/overtime'
  passing xmltype(:overtime_data)
  columns ot_empid nvarchar2(10) path 'employee_id',
    ot_date date path 'date',
    ot_hour number(4,0) path 'overtime_hour'
) x;

OT_EMPID   OT_DATE      OT_HOUR
---------- --------- ----------
invalidval 15-JAN-16       1235

XML元素的12个字符值被截断以适合columns子句。还要注意小时数是四舍五入以适应约束数字类型 - 1234.5向上舍入到1235.(只要该值可以转换为指定的精度,它就不会抱怨。基本上这意味着只要在小数点前不要超过四位数它将被舍入;如果在小数点前有五位或更多位数,它将得到一个ORA-01438。)

如果您尝试插入这些值,则不会抱怨,因为它们对表定义有效:

insert into tbl_overtime (ot_empid, ot_date, ot_hour)
select x.ot_empid, x.ot_date, x.ot_hour
from xmltable('/overtime'
  passing xmltype(:overtime_data)
  columns ot_empid nvarchar2(10) path 'employee_id',
    ot_date date path 'date',
    ot_hour number(4,0) path 'overtime_hour'
) x;

1 row inserted.

如果您在插入之前不打算验证或操作该值,并且如果XML节点值超过10个字符,您确实希望它出错,那么使XMLTable列数据类型甚至更大的一个字符将起作用。 (如果你要验证值,那么你可以把它做得更大;但是这里的任何东西都会超过10个。)

   INSERT INTO TBL_OVERTIME SELECT x.* FROM XMLTABLE('/overtime'
                                                PASSING xmlData
                                                COLUMNS OT_EMPID   NVARCHAR2(11)     PATH   'employee_id',
                                                        OT_DATE   DATE     PATH    'date',        
                                                        OT_HOUR   NUMBER(4,0)    PATH    'overtime_hour'                                                        
                                                        ) x;

如果路径中的值超过10个字符,则x.ot_empid值将被截断为11个字符,然后插入将失败,因为它对于实际表列而言太大。

使用与以前相同的数据进行演示;

select x.ot_empid, x.ot_date, x.ot_hour
from xmltable('/overtime'
  passing xmltype(:overtime_data)
  columns ot_empid nvarchar2(11) path 'employee_id',
    ot_date date path 'date',
    ot_hour number(4,0) path 'overtime_hour'
) x;

OT_EMPID    OT_DATE      OT_HOUR
----------- --------- ----------
invalidvalu 15-JAN-16       1235

注意ot_empid列现在有11个字符。现在插入失败:

insert into tbl_overtime (ot_empid, ot_date, ot_hour)
select x.ot_empid, x.ot_date, x.ot_hour
from xmltable('/overtime'
  passing xmltype(:overtime_data)
  columns ot_empid nvarchar2(11) path 'employee_id',
    ot_date date path 'date',
    ot_hour number(4,0) path 'overtime_hour'                                                        
) x;

Error report -
SQL Error: ORA-12899: value too large for column "SCHEMA"."TBL_OVERTIME"."OT_EMPID" (actual: 11, maximum: 10)