¿Cómo obtengo varias columnas para usar en un ciclo de cursor?

88

Cuando intento ejecutar el siguiente fragmento de código SQL dentro de un bucle de cursor,

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

Recibo el siguiente mensaje,

Msg 15248, nivel 11, estado 1, procedimiento sp_rename, línea 213
O el parámetro @objnamees ambiguo o el reclamo @objtype(COLUMN) es incorrecto.

¿Qué está mal y cómo lo soluciono? Intenté poner el nombre de la columna entre corchetes []y comillas dobles, ""como sugirieron algunos de los resultados de búsqueda.

Editar 1 -

Aquí está el guión completo. ¿Cómo paso el nombre de la tabla al cambio de nombre sp? No estoy seguro de cómo hacerlo, ya que los nombres de las columnas están en una de las muchas tablas.

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

Edición 2: el script está diseñado para cambiar el nombre de las columnas cuyos nombres coinciden con un patrón, en este caso con un prefijo "pct". Las columnas se encuentran en una variedad de tablas dentro de la base de datos. Todos los nombres de las tablas tienen el prefijo "TestData".

Joe
fuente
1
esta línea concatena una cadena. ¿Por qué no lo imprime para que pueda ver el contenido de la cadena?
Preet Sangha
Si @test contiene un nombre calificado, debe estar entre apóstrofos. Si se cumple la misma suposición, right () eliminará los primeros tres caracteres en el nombre de la tabla; si deseaba reemplazar los últimos caracteres del nombre de la columna, este sería LEFT. ¿Podría expandir el script un poco agregando set @test = ...?
Nikola Markovinović
Su código realmente me ayudó a resolver mi problema, ¡gracias por eso!
Neville

Respuestas:

157

Aquí hay una versión ligeramente modificada. Los cambios se indican como comentario de código.

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ć
fuente
2
Una de mis respuestas favoritas en SO.
Rubens Mariuzzo
@RubensMariuzzo Gracias, estás siendo demasiado generoso :-)
Nikola Markovinović
62
TLDR; FETCH NEXT FROM db_cursor INTO @var1, @ var2
Don Rolling
7
TLDR se usa comúnmente para indicar una versión corta de una información más larga. Significa demasiado tiempo no leído. Estaba sugiriendo que hay una versión más corta de la respuesta que diste y yo la di.
Don Rolling
1
Buen toque, no buscar dos veces. :)
Winner_joiner