Bagaimana cara mengambil beberapa kolom untuk digunakan dalam lingkaran kursor?

90

Ketika saya mencoba menjalankan potongan SQL berikut di dalam lingkaran kursor,

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

Saya mendapatkan pesan berikut,

Msg 15248, Level 11, Status 1, Prosedur sp_rename, Baris 213
Entah parameternya @objnameambigu atau diklaim @objtype(COLUMN) salah.

Apa yang salah dan bagaimana cara memperbaikinya? Saya mencoba membungkus nama kolom dalam tanda kurung [], dan tanda kutip ganda ""seperti beberapa hasil pencarian yang disarankan.

Edit 1 -

Ini seluruh skripnya. Bagaimana cara mengirimkan nama tabel ke rename sp? Saya tidak yakin bagaimana melakukannya karena nama kolom ada di salah satu dari banyak tabel.

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

Sunting 2 - Skrip dirancang untuk mengganti nama kolom yang namanya cocok dengan pola, dalam hal ini dengan awalan "pct". Kolom muncul di berbagai tabel dalam database. Semua nama tabel diawali dengan "TestData".

Joe
sumber
1
baris ini menggabungkan string. mengapa Anda tidak mencetaknya sehingga Anda dapat melihat apa isi string itu,
Preet Sangha
@testmemiliki bentuk table.columnatauschema.table.column , bukan?
GSerg
Jika @test berisi nama yang memenuhi syarat, maka harus diberi tanda apostrof. Jika asumsi yang sama berlaku, right () akan menghapus tiga karakter pertama dalam nama tabel; di Anda ingin mengganti karakter terakhir dari nama kolom ini akan menjadi LEFT. Bisakah Anda memperluas skrip sedikit dengan menambahkan set @test = ...?
Nikola Markovinović
Kode Anda benar-benar membantu saya memecahkan masalah saya - terima kasih untuk itu!
Neville

Jawaban:

159

Ini adalah versi yang sedikit dimodifikasi. Perubahan dicatat sebagai komentar kode.

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ć
sumber
2
Salah satu jawaban favorit saya di SO.
Rubens Mariuzzo
@RubensMariuzzo Terima kasih, Anda terlalu murah hati :-)
Nikola Markovinović
63
TLDR; FETCH NEXT FROM dbcursor INTO @var1, @ var2
Don Rolling
8
TLDR biasanya digunakan untuk menunjukkan versi pendek dari informasi yang lebih panjang. Itu singkatan dari Too Long Didn't Read. Saya menyarankan bahwa ada versi yang lebih pendek dari jawaban yang Anda berikan dan saya berikan.
Don Rolling
1
Sentuhan yang bagus, tidak mengambil dua kali. :)
winner_joiner