J'essaie de déterminer si une colonne d'Oracle est renseignée à partir d'une séquence. Mon impression de la façon dont Oracle gère le séquençage est que la séquence et la colonne sont des entités distinctes et que vous devez insérer manuellement la valeur de séquence suivante, telle que:
insert into tbl1 values(someseq.nextval, 'test')
ou le mettre dans un déclencheur de table. Cela signifie qu'il est non trivial de dire si une colonne est remplie à partir d'une séquence. Est-ce exact? Avez-vous des idées sur la manière de déterminer si une colonne est renseignée à partir d'une séquence?
Vous avez raison; la séquence est distincte de la table et une seule séquence peut être utilisée pour renseigner n'importe quelle table et les valeurs d'une colonne dans une table peuvent généralement provenir d'une séquence (ou d'un ensemble de séquences), à l'exception des valeurs générées manuellement.
En d'autres termes, il n'y a pas de connexion obligatoire entre une colonne et une séquence - et donc aucun moyen de découvrir une telle relation à partir du schéma.
En fin de compte, l'analyse portera sur le code source de toutes les applications qui insèrent ou mettent à jour des données dans la table. Rien d'autre n'est garanti. Vous pouvez réduire l'étendue de la recherche si une procédure stockée est le seul moyen d'apporter des modifications à la table, ou s'il existe un déclencheur qui définit la valeur, ou autre. Mais la solution générale est la "non-solution" de "analyser la source".
Si la séquence est utilisée dans un déclencheur, il est possible de trouver les tables qu’elle remplit:
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>
Vous pouvez modifier cette requête pour rechercher des procédures stockées, etc. qui utilisent la séquence.
Il n'y a pas de liens de métadonnées directs entre les séquences Oracle et aucune utilisation dans la base de données. Vous pouvez deviner intelligemment si les valeurs d'une colonne sont liées à une séquence en interrogeant les métadonnées USER_SEQUENCES et en comparant la colonne LAST_NUMBER aux données de la colonne.
Comme Jonathan l'a souligné: il n'y a pas de moyen direct de relier les deux objets. Toutefois, si vous "conservez un standard" pour les clés primaires et les séquences/déclencheurs, vous pouvez le découvrir en recherchant la clé primaire, puis en associant la contrainte à la séquence de la table.
J'avais besoin de quelque chose de similaire car nous construisions un produit multi-db et j'ai essayé de répliquer certaines classes avec des propriétés trouvées dans un objet DataTable de .Net qui a AutoIncrement, IncrementSeed et IncrementStep, qui ne peuvent être trouvées que dans les séquences.
Ainsi, comme je l'ai dit, si vous utilisez pour vos tables une PK et que vous avez toujours une séquence associée à un déclencheur d'insertions sur une table, cela peut s'avérer utile:
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;
Cela vous donnerait la liste des colonnes pour un schéma/table avec:
Je suis presque sûr que le code peut être optimisé, mais cela fonctionne pour moi. Je l'utilise pour "charger des métadonnées" dans les tables, puis représenter ces métadonnées en tant qu'entités sur mon interface.
Notez que je ne filtre que les clés primaires et ne récupère pas les contraintes de clés composées car je ne me soucie pas de celles-ci. Si vous le faites, vous devrez modifier le code pour le faire et vous assurer de filtrer les doublons, car vous pourriez obtenir une colonne deux fois (une pour la contrainte PK, une autre pour la clé composée).
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'