Como faço para buscar várias colunas para uso em um loop de cursor?

90

Quando tento executar o seguinte snippet SQL dentro de um loop de cursor,

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

Eu recebo a seguinte mensagem,

Msg 15248, nível 11, estado 1, procedimento sp_rename, linha 213
O parâmetro @objnameé ambíguo ou o reivindicado @objtype(COLUMN) está incorreto.

O que está errado e como faço para corrigir isso? Tentei colocar o nome da coluna entre colchetes []e aspas duplas, ""como alguns dos resultados da pesquisa sugeridos.

Editar 1 -

Aqui está o roteiro completo. Como passo o nome da tabela para renomear sp? Não tenho certeza de como fazer isso, pois os nomes das colunas estão em uma das muitas tabelas.

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

Editar 2 - O script é projetado para renomear colunas cujos nomes correspondem a um padrão, neste caso com um prefixo "pct". As colunas ocorrem em várias tabelas no banco de dados. Todos os nomes de tabela são prefixados com "TestData".

Joe
fonte
1
esta linha concatena uma string. por que você não imprime para ver o conteúdo da string,
Preet Sangha
@testtem a forma de table.columnouschema.table.column , não é?
GSerg
Se @test contiver um nome qualificado, ele precisa estar entre apóstrofos. Se a mesma suposição for válida, right () removerá os primeiros três caracteres do nome da tabela; se você quisesse substituir os últimos caracteres do nome da coluna, isso seria LEFT. Você poderia expandir o script um pouco adicionando set @test = ...?
Nikola Markovinović
Seu código realmente me ajudou a resolver meu problema - obrigado por isso!
Neville,

Respostas:

159

Aqui está a versão ligeiramente modificada. As alterações são anotadas como comentários 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ć
fonte
2
Uma das minhas respostas favoritas no SO.
Rubens Mariuzzo
@RubensMariuzzo Obrigado, você está sendo muito generoso :-)
Nikola Markovinović
63
TLDR; BUSQUE A SEGUINTE DE db_cursor INTO @var1, @ var2
Don Rolling
8
O TLDR é comumente usado para indicar uma versão resumida de uma informação mais longa. Significa muito tempo não lido. Eu estava sugerindo que há uma versão mais curta da resposta que você deu e eu a dei.
Don Rolling
1
Toque agradável, sem buscar duas vezes. :)
vencedor_joiner