Position du problème :
Vous cherchez à transférer des données entre deux bases SQL Server, mais souhaitez respecter les contraintes de clés primaires lors de ces transferts.
Vous êtes donc confrontés à ce type de problème :
Si un CLUB de course à pied est défini sur une LIGUE on a une Foreign key entre le club et sa ligne et il faut donc insérer d'abord les données des ligues et ensuite les données des clubs.
Exemple de données :
LIGUE :
H-N Haute Normandie
CLUB
1234 Stade Dieppois H-N
4321 Sports Loisirs Aliermontais H-N
Ce problème se répète de manière récursive si on a des coureurs enregistré sur des clubs..
Une foreign key du coureur pointe sur le CLUB; et l'ordre final des tables sera donc
LIGUE
CLUB
COUREUR
Comment généraliser et automatiser tout cela ?
Utilisation des vues du système :
Nous allons pour ce faire utiliser deux vues sur les tables et objets du systèmes :
sys.foreign_keys qui nous donne les couples (référenceur, référencé)
et
INFORMATION_SCHEMA.TABLES qui nous donne les noms des tables utilisateur
voyons ces deux vues en exécution :
select
name
as NomContrainte,
object_name(parent_object_id)
as Referenceur,
object_name(referenced_object_id)
as Reference
from
sys.foreign_keys
......
select table_NAME from
INFORMATION_SCHEMA.tableS
where table_TYPE =
'BASE table'
.....
Corps de l'algorithme :
Le principe de l'algorithme est le suivant :
on cherche des tables qui ne sont pas référencées par d'autres et on les supprime de la liste des tables à traiter.
On continue ce process jusqu'à l'une des conditions :
- le nombre de tables à traiter est arrivé à 0
- le nombre de tables à traiter ne diminue plus, ce qui peut se produire dans les cas suivants : récursivité sur des références, self-référence,...
L'algorithme est donc perfectible : à vos claviers...
Code source complet :
set
nocount
on
declare @tablesATraiter table
(Nomtable sysname)
declare @tablesHierarchisees table
(Nomtable sysname, NoOrdre int
identity(1,1))
declare @iResteATraiter int
declare @iResteATraiterPrec int
-- A priori nous traitons toutes les tables de la base
insert
into @tablesATraiter
select table_NAME from
INFORMATION_SCHEMA.tableS
where table_TYPE =
'BASE table'
set @iResteATraiterPrec =
-1
select @iResteATraiter =
count(*)
from @tablesATraiter
while 1=1
begin
if @iResteATraiter < 1
break
-- on a fini
if @iResteATraiterPrec = @iResteATraiter
break
-- on ne peut plus évoluer
print
'Il reste '
+
str(@iResteATraiter)
+
' tables à traiter '
-- Affichage de test éventuel si pb :
-- select Referenceur.Nomtable,name,Reference.Nomtable
-- from @tablesATraiter Referenceur inner join sys.foreign_keys FK
-- on Referenceur.Nomtable = object_name(FK.parent_object_id)
-- inner join @tablesATraiter Reference
-- on object_name(FK.referenced_object_id) = Reference.Nomtable
-- Trouver celles qui ne référencent aucune des tables restant à traiter
insert
into @tablesHierarchisees
select Nomtable from @tablesATraiter
where Nomtable not
in
(
select Referenceur.Nomtable
from @tablesATraiter Referenceur inner
join
sys.foreign_keys FK
on Referenceur.Nomtable =
object_name(FK.parent_object_id)
inner
join @tablesATraiter Reference
on
object_name(FK.referenced_object_id)
= Reference.Nomtable )
select
*
from @tablesHierarchisees
delete
from @tablesATraiter
where Nomtable in
(select Nomtable from @tablesHierarchisees)
set @iResteATraiterPrec = @iResteATraiter
select @iResteATraiter =
count(*)
from @tablesATraiter
end
print
'Il reste '
+
str(@iResteATraiter)
+
' tables à traiter '
select
*
from @tablesATraiter
print
'Résultat de la hiérarchie : '
select
*
from @tablesHierarchisees
Vérification de l'exécution :
Commentaires : comme indiqué, si des self références ont été définies, l'algorithme ne peut traiter la table en question :
cela sera de toute façon délicat
qui a commencé l'œuf ou la poule ??
Conclusion
Ce morceau de code est un préalable à des traitements plus sérieux, il reste bien sûr à compléter avec les copies de votre choix :
insert select,
bulk insert
ligne à ligne
....
Utilisation de SSIS
....
le principe étant de le faire dans l'ordre des clés primaires.