2014-09-26 90 views
1

我試圖動態創建代碼以將列定義更改爲字段的最大長度。動態T-SQL - 將列定義更改爲字段的最大長度

請注意,數據庫的內容不會改變。

這是我到目前爲止,但我不能單獨執行最大長度查詢來獲得一個數字。我哪裏錯了?

問候。

DECLARE @SQL_STMT VARCHAR(MAX) = '' 

SELECT @SQL_STMT = @SQL_STMT 
    + '''ALTER TABLE ' 
    + TABLE_NAME 
    + ' ALTER COLUMN ' 
    + COLUMN_NAME 
    + ' ' 
    + DATA_TYPE 
    + '('' SELECT MAX(LEN(' 
    + COLUMN_NAME 
    + ')) FROM ' 
    + TABLE_NAME 
    + ''') '' 
    ' 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE DATA_TYPE = 'varchar' 

PRINT(@SQL_STMT) 
+0

你想改變VARCHAR列高達多少長度???這真的不清楚你想要做什麼? – 2014-09-26 15:08:38

+0

直到單個字段的最大長度。例如,從emp – 2014-09-26 15:10:35

+2

選擇max(len(empname))爲什麼在世界上你會這樣做?這可能會削弱使用此數據庫的應用程序。您可以開始截斷數據錯誤,因爲前端已驗證。你不會從中獲益,因爲你只是在改變varchar列。更何況,你可能會得到錯誤,因爲你使用的LEN沒有考慮尾隨空格。 – 2014-09-26 15:15:07

回答

0

編輯我的第一個版本不精不夠,這裏要說的是我已經測試了新版本:

DECLARE @SQL_STMT VARCHAR(MAX) = 'DECLARE @query nvarchar(max);' 

SELECT @SQL_STMT = @SQL_STMT 
    + 'SET @query =''ALTER TABLE ' 
    + TABLE_NAME 
    + ' ALTER COLUMN ' 
    + COLUMN_NAME 
    + ' ' 
    + DATA_TYPE 
    + '('' +CAST((SELECT MAX(DATALENGTH(' 
    + COLUMN_NAME 
    + ')) FROM ' 
    + TABLE_NAME 
    + ') as nvarchar(max))+'') '' 
    exec(@query);' 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE DATA_TYPE = 'nvarchar' 

PRINT(@SQL_STMT) 
+0

你有沒有試過這段代碼?它是編譯? – 2014-09-26 15:20:16

+0

我的第一個版本沒有工作(我沒有沙箱數據庫嘗試),但我已經編輯了我的答案與功能的解決方案。 – Ndech 2014-09-26 15:34:05

+0

乾杯隊友!我會盡管使用數據長度,而不是@DrCopyPaste說 – 2014-09-26 15:42:06

-1

您不能使用SELECT陳述或整數變量作爲大小ALTER TABLE聲明中的列。通常,不能在相同的語句中混合DDL(數據描述語言,例如,CREATE,ALTER,DROP)和DML(數據操作語言,例如,SELECTINSERT,UPDATE)。

這意味着你必須使用動態SQL來完成任務。您將無法使用動態SQL來構建可保存和重用的靜態SQL。您需要檢索該字段的最大長度並將其保存到一個變量,然後構造語句ALTER,最後EXEC()ALTER語句。最簡單的方法是使用光標INFORMATION_SCHEMA.COLUMNS,但也可以使用雙重動態SQL。也就是說,動態SQL本身可以生成動態SQL。然而,這很難調試。

除此之外,我質疑你正在嘗試做什麼的有效性。簡而言之,你永遠不需要使用這個代碼。數據庫模式應該是相對固定的,因爲改變它對性能有重大影響。通過改變列的大小,你告訴數據庫引擎它需要改變它在物理上將數據存儲在磁盤上的方式,這不是你應該輕鬆​​或定期做的事情。只需將足夠大的值設置爲足以滿足用戶需求,您就可以做得更好。現代關係數據庫不能低效地存儲數據,但改變列大小通常仍然是不好的做法。

0

我的想法不是朋友,但是這應該做你想要什麼:

DECLARE @SQL_STMT VARCHAR(MAX) = '' 

SELECT 
    IDENTITY(int,1,1) as ID, -- for later update 
    'ALTER TABLE ' 
    + c.TABLE_NAME 
    + ' ALTER COLUMN ' 
    + c.COLUMN_NAME 
    + ' ' 
    + c.DATA_TYPE 
    + '(' P1 

    , ' MAX(LEN(' 
    + c.COLUMN_NAME 
    + ')' 
    +') FROM ' 
    + c.TABLE_NAME P2 

    , ') ' P3 
into #tmp  
FROM INFORMATION_SCHEMA.Tables t 
JOIN INFORMATION_SCHEMA.Columns c 
on c.TABLE_CATALOG= t.TABLE_CATALOG 
    and c.TABLE_SCHEMA=t.TABLE_SCHEMA 
    and c.TABLE_NAME=t.TABLE_NAME 
where TABLE_TYPE='BASE TABLE' -- only Tables not views 
and DATA_TYPE = 'varchar' 

Select @SQL_STMT='' -- collect ID + Max info e.g. SELECT 1, MAX(LEN(FirstName)) FROM user_info 
Select @[email protected]_STMT + 'SELECT '+ CAST(ID as varchar(10)) + ', '+ P2 +CHAR(13) 
from #tmp 

Declare @a table (ID Integer,Size Integer) -- table for ID and Len 
--print @SQL_STMT 

insert into @a Exec (@SQL_STMT) -- fill table by executing block 

        -- define a minimum size if 0 
Update #tmp set P2 = Case When Size<1 then 1 else Size end -- update p2 
From @a a where a.ID = #tmp.ID 

Select @SQL_STMT='' 
Select @[email protected]_STMT + P1 + P2 + P3 +CHAR(13) 
from #Tmp 

print @SQL_STMT 

Exec(@SQL_STMT) 


Drop table #tmp