Position du problème :
Devant développer des procédures génériques pour un client, je me suis posé la question suivante :
comment obtenir une liste CSV des colonnes constituant la clé primaire d'une table?
Et, au delà de ce problème particulier, comment obtenir une chaine à partir d'un resultset.
En effet, les vues sur le catalogue nous donne des ensembles résultats, ainsi :
select
*
from
information_schema.table_CONSTRAintS
donne :
et, dans le même ordre d'idées, il est facile d'obtenir un data set des colonnes de clé primaire (mon besoin de départ) :
select
*
from
information_schema.table_CONSTRAintS pk
inner
join
information_schema.CONSTRAint_COLUMN_USAGE col
on pk.table_CATALOG = col.table_CATALOG and
pk.table_SCHEMA = col.table_SCHEMA and
pk.table_NAME = col.table_NAME
where CONSTRAint_TYPE =
'primary key'
Bien, mais tout cela nous donne des datasets, pas un CSV ?
C'est là où intervient le raisonnement récursif :
. si j'avais cette liste à l''étape n-1 (c'est à dire les n-1 colonnes constituant la clé primaire), alors la suite serait :
ListeAn-1 CONCATENATION ',' CONCATENATION Colonnen
sachant que la liste au départ est vide....
c'est le but de la fonction écrité ci dessous :
create
function ColonnesPk (@NomSchema sysname,@Nomtable sysname)
returnS
nvarchar(max)
AS
begin
declare @csColonnesPk varchar(max)
declare @csSeparateur varchar(10)
-- Requête récursive sur les colonnes de la clé primaire
set @csColonnesPk =
''
set @csSeparateur =
''
select
top 20 @csColonnesPk = @csColonnesPk + @csSeparateur + COLUMN_NAME ,@csSeparateur =
','
from
information_schema.table_CONSTRAintS pk
inner
join
information_schema.CONSTRAint_COLUMN_USAGE col
on pk.table_CATALOG = col.table_CATALOG and
pk.table_SCHEMA = col.table_SCHEMA and
pk.table_NAME = col.table_NAME
where pk.table_CATALOG =
db_name()
and
pk.table_SCHEMA = @NomSchema and
pk.table_NAME = @Nomtable
return @csColonnesPk
end
go
Quelques explications :
le séparateur sert à séparer les colonnes de la liste, il est donc à '' au départ, puis passe à ',' par la suite.
En effet on a une construction du style
{Vide}{Vide}{Clé0}{,}{Clé1}{,}
etc...
l'astuce est basée sur le fait que le dataset se déroule ligne à ligne, et donc nous permet de contaténer le tout dans @csColonnesPk.
Testons le tout :
print dbo.ColonnesPk ('dbo','TRD')
go
CHRONO,NAME,PROJECT
Magique, nest-ce pas ?!
Le tout est bien sûr généralisable à tout problème de ce type, par exemple :
--
-- Toutes les colonnes d'une table (sauf celle qui se nomme TRANSMIS)
--
create
function Colonnes (@NomSchema sysname,@Nomtable sysname,@Prefixe nvarchar(max))
returnS
nvarchar(max)
AS
begin
declare @csColonnes varchar(max)
declare @csSeparateur varchar(10)
-- Requête récursive sur les colonnes
set @csColonnes =
''
set @csSeparateur =
''
select
top 200 @csColonnes = @csColonnes + @Prefixe + @csSeparateur + COLUMN_NAME , @csSeparateur =
','
from
information_schema.COLUMNS
where table_CATALOG =
db_name()
and
table_SCHEMA = @NomSchema and
table_NAME = @Nomtable and
COLUMN_NAME <>
'TRANSMIS'
return @csColonnes
end
go
qui donne :
PROJECT,CHRONO,RECTS,STATION,UNITNAME,VARTYPE,NAME,TITLE,.....
Conclusion :
Encore un moyen d'éviter les curseurs qui, décidément, ne sont pas un des points forts de SQLServer ... ceux qui lisent mes articles, savent que, heureusement je suis très satisfait de beaucoup d'autres aspects.