Comment récupérer plusieurs colonnes à utiliser dans une boucle de curseur?

88

Lorsque j'essaye d'exécuter l'extrait de code SQL suivant dans une boucle de curseur,

set @cmd = N'exec sp_rename ' + @test + N',' +
           RIGHT(@test,LEN(@test)-3) + '_Pct' + N',''COLUMN'''

Je reçois le message suivant,

Msg 15248, niveau 11, état 1, procédure sp_rename, ligne 213
Soit le paramètre @objnameest ambigu, soit la réclamation @objtype(COLUMN) est erronée.

Qu'est-ce qui ne va pas et comment y remédier? J'ai essayé de mettre le nom de la colonne entre crochets []et des guillemets doubles ""comme certains des résultats de recherche suggérés.

Modifier 1 -

Voici le script complet. Comment puis-je passer le nom de la table au rename sp? Je ne sais pas comment faire cela, car les noms de colonnes sont dans l'une des nombreuses tables.

BEGIN TRANSACTION

declare @cnt int
declare @test nvarchar(128)
declare @cmd nvarchar(500) 
declare Tests cursor for
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME LIKE 'pct%' AND TABLE_NAME LIKE 'TestData%'

open Tests
fetch next from Tests into @test
while @@fetch_status = 0
BEGIN
  set @cmd = N'exec sp_rename ' + @test + N',' + RIGHT(@test,LEN(@test)-3) + '_Pct' + N', column' 

  print @cmd

  EXEC sp_executeSQL @cmd

  fetch next from Tests into @test
END

close Tests 
deallocate Tests


ROLLBACK TRANSACTION
--COMMIT TRANSACTION

Edit 2 - Le script est conçu pour renommer les colonnes dont les noms correspondent à un modèle, dans ce cas avec un préfixe "pct". Les colonnes se trouvent dans diverses tables de la base de données. Tous les noms de table sont préfixés par "TestData".

Joe
la source
1
cette ligne concatène une chaîne. pourquoi ne pas l'imprimer pour voir le contenu de la chaîne,
Preet Sangha
@testa la forme de table.columnouschema.table.column , n'est-ce pas?
GSerg
Si @test contient un nom qualifié, il doit être en apostrophes. Si la même hypothèse est vraie, right () supprimera les trois premiers caractères du nom de la table; dans vous vouliez remplacer les derniers caractères du nom de colonne ce serait LEFT. Pourriez-vous développer un peu le script en ajoutant set @test = ...?
Nikola Markovinović
Votre code m'a aidé à résoudre mon problème - merci pour cela!
Neville

Réponses:

157

Voici une version légèrement modifiée. Les modifications sont notées sous forme de commentaire de code.

BEGIN TRANSACTION

declare @cnt int
declare @test nvarchar(128)
-- variable to hold table name
declare @tableName nvarchar(255)
declare @cmd nvarchar(500) 
-- local means the cursor name is private to this code
-- fast_forward enables some speed optimizations
declare Tests cursor local fast_forward for
 SELECT COLUMN_NAME, TABLE_NAME
   FROM INFORMATION_SCHEMA.COLUMNS 
  WHERE COLUMN_NAME LIKE 'pct%' 
    AND TABLE_NAME LIKE 'TestData%'

open Tests
-- Instead of fetching twice, I rather set up no-exit loop
while 1 = 1
BEGIN
  -- And then fetch
  fetch next from Tests into @test, @tableName
  -- And then, if no row is fetched, exit the loop
  if @@fetch_status <> 0
  begin
     break
  end
  -- Quotename is needed if you ever use special characters
  -- in table/column names. Spaces, reserved words etc.
  -- Other changes add apostrophes at right places.
  set @cmd = N'exec sp_rename ''' 
           + quotename(@tableName) 
           + '.' 
           + quotename(@test) 
           + N''',''' 
           + RIGHT(@test,LEN(@test)-3) 
           + '_Pct''' 
           + N', ''column''' 

  print @cmd

  EXEC sp_executeSQL @cmd
END

close Tests 
deallocate Tests

ROLLBACK TRANSACTION
--COMMIT TRANSACTION
Nikola Markovinović
la source
2
Une de mes réponses préférées dans SO.
Rubens Mariuzzo
@RubensMariuzzo Merci, vous êtes trop généreux :-)
Nikola Markovinović
62
TLDR; FETCH NEXT FROM db_cursor INTO @var1, @ var2
Don Rolling
7
TLDR est couramment utilisé pour indiquer une version courte d'une information plus longue. Cela signifie Too Long Didn't Read. Je suggérais qu'il existe une version abrégée de la réponse que vous avez donnée et je l'ai donnée.
Don Rolling
1
Nice Touch, ne pas aller chercher deux fois. :)
winner_joiner