我试图弄清楚Oracle中的列是否从序列中填充。我对Oracle如何处理排序的印象是序列和列是单独的实体,需要手动插入下一个序列值,如:
insert into tbl1 values(someseq.nextval, 'test')
或将其放入表触发器中。这意味着判断列是否从序列中填充是非常重要的。那是对的吗?关于如何确定列是否从序列填充的任何想法?
答案 0 :(得分:20)
你是对的;序列与表分开,单个序列可用于填充任何表,并且某些表中列中的值可能主要来自序列(或序列集),但手动生成的值除外。 / p>
换句话说,列和序列之间没有强制连接 - 因此无法从架构中发现这种关系。
最终,分析将是在表中插入或更新数据的所有应用程序的源代码。没有其他保证。如果存储过程是对表进行修改的唯一方法,或者存在设置值或其他此类事物的触发器,则可以缩小搜索范围。但一般的解决方案是“分析来源”的“非解决方案”。
答案 1 :(得分:11)
如果在触发器中使用序列,则可以找到它填充的表:
SQL> select t.table_name, d.referenced_name as sequence_name
2 from user_triggers t
3 join user_dependencies d
4 on d.name = t.trigger_name
5 where d.referenced_type = 'SEQUENCE'
6 and d.type = 'TRIGGER'
7 /
TABLE_NAME SEQUENCE_NAME
------------------------------ ------------------------------
EMP EMPNO_SEQ
SQL>
您可以更改此查询以查找使用序列的存储过程等。
答案 2 :(得分:2)
Oracle序列与数据库中的任何使用之间没有直接的元数据链接。如果列的值与序列相关,您可以通过查询USER_SEQUENCES元数据并将LAST_NUMBER列与列的数据进行比较来进行智能猜测。
答案 3 :(得分:1)
正如乔纳森所指出的那样:没有直接的方法可以将两个物体联系起来。但是,如果您为主键和序列/触发器“保持标准”,则可以通过查找主键找出,然后将约束与表序列相关联。
我需要类似的东西,因为我们正在构建一个多db产品,并且我试图复制一些具有在.Net的DataTable对象中找到的属性的类,它们具有AutoIncrement,IncrementSeed和IncrementStep,这些只能在序列。
所以,正如我所说,如果您对于您的表使用PK并且总是有一个与触发器相关联的序列,那么这可能会很方便:
select tc.table_name,
case tc.nullable
when 'Y' then 1
else 0
end as is_nullable,
case ac.constraint_type
when 'P' then 1
else 0
end as is_identity,
ac.constraint_type,
seq.increment_by as auto_increment_seed,
seq.min_value as auto_increment_step,
com.comments as caption,
tc.column_name,
tc.data_type,
tc.data_default as default_value,
tc.data_length as max_length,
tc.column_id,
tc.data_precision as precision,
tc.data_scale as scale
from SYS.all_tab_columns tc
left outer join SYS.all_col_comments com
on (tc.column_name = com.column_name and tc.table_name = com.table_name)
LEFT OUTER JOIN SYS.ALL_CONS_COLUMNS CC
on (tc.table_name = cc.table_name and tc.column_name = cc.column_name and tc.owner = cc.owner)
LEFT OUTER JOIN SYS.ALL_CONSTRAINTS AC
ON (ac.constraint_name = cc.constraint_name and ac.owner = cc.owner)
LEFT outer join user_triggers trg
on (ac.table_name = trg.table_name and ac.owner = trg.table_owner)
LEFT outer join user_dependencies dep
on (trg.trigger_name = dep.name and dep.referenced_type='SEQUENCE' and dep.type='TRIGGER')
LEFT outer join user_sequences seq
on (seq.sequence_name = dep.referenced_name)
where tc.table_name = 'TABLE_NAME'
and tc.owner = 'SCHEMA_NAME'
AND AC.CONSTRAINT_TYPE = 'P'
union all
select tc.table_name,
case tc.nullable
when 'Y' then 1
else 0
end as is_nullable,
case ac.constraint_type
when 'P' then 1
else 0
end as is_identity,
ac.constraint_type,
seq.increment_by as auto_increment_seed,
seq.min_value as auto_increment_step,
com.comments as caption,
tc.column_name,
tc.data_type,
tc.data_default as default_value,
tc.data_length as max_length,
tc.column_id,
tc.data_precision as precision,
tc.data_scale as scale
from SYS.all_tab_columns tc
left outer join SYS.all_col_comments com
on (tc.column_name = com.column_name and tc.table_name = com.table_name)
LEFT OUTER JOIN SYS.ALL_CONS_COLUMNS CC
on (tc.table_name = cc.table_name and tc.column_name = cc.column_name and tc.owner = cc.owner)
LEFT OUTER JOIN SYS.ALL_CONSTRAINTS AC
ON (ac.constraint_name = cc.constraint_name and ac.owner = cc.owner)
LEFT outer join user_triggers trg
on (ac.table_name = trg.table_name and ac.owner = trg.table_owner)
LEFT outer join user_dependencies dep
on (trg.trigger_name = dep.name and dep.referenced_type='SEQUENCE' and dep.type='TRIGGER')
LEFT outer join user_sequences seq
on (seq.sequence_name = dep.referenced_name)
where tc.table_name = 'TABLE_NAME'
and tc.owner = 'SCHEMA_NAME'
AND AC.CONSTRAINT_TYPE is null;
这将为您提供模式/表的列列表:
我很确定代码可以优化,但它适用于我,我用它来为表“加载元数据”,然后将元数据表示为我前端的实体。
请注意,我只过滤主键而不检索复合键约束,因为我不关心它们。如果你这样做,你将不得不修改代码,并确保你过滤重复,因为你可以得到一个列两次(一个用于PK约束,另一个用于复合键)。
答案 4 :(得分:1)
select t.table_name,
d.referenced_name as sequence_name,
d.REFERENCED_OWNER as "OWNER",
c.COLUMN_NAME
from user_trigger_cols t, user_dependencies d, user_tab_cols c
where d.name = t.trigger_name
and t.TABLE_NAME = c.TABLE_NAME
and t.COLUMN_NAME = c.COLUMN_NAME
and d.referenced_type = 'SEQUENCE'
and d.type = 'TRIGGER'