使用 Select 語句從同一個表中獲取列名和表名
我有一個包含 2 列的表:Column1 (
table_name
) 和 column2 (column_name
),如下所示:
(Column 1) (Column 2) |Column_Name | Table_Name | -------------|------------| |Address | TBL_Person| |Email | TBL_User |
它有大約300條記錄
我想要一個返回這 2 列的 select 語句和一個獲取表列的最大長度的列
像這樣 :
|Column_Name | Table_Name | Max_Length | -------------|------------|------------| |Address | TBL_Person| 1020 | |Email | TBL_User | 50 |
我可以製作一個計算 max_length 的字元串,但我不知道如何在 select 語句中使用它。
我嘗試使用函式,但在函式中我必須執行函式中不允許的 SQL,因為你不能在函式中使用 sp。
COL_LENGTH
返回列的預設長度,而不是最大長度。我擁有的所有列都是varchar(max)或nvarchar(max)。
目前沒有語法直接支持您正在嘗試做的事情。您可能知道,名稱不能在 SQL 語句中參數化。這意味著當您需要從另一個表的列值中替換名稱時,您必須使用動態 SQL:首先建構查詢字元串,然後執行它。在這種情況下,使用動態 SQL 是沒有辦法的。此外,您已經為自己確定了不能在函式中使用動態 SQL。所以你來了,看起來很難過。
但是,如果您堅持為此使用單個 SELECT 語句,則有一種方法 - 前提是您同意稍微向後彎腰以實現目標,即。並接受該方法的主要限制。
該解決方案涉及創建環回連結伺服器並使用 OPENQUERY 函式。但首先您需要確保您的動態 SQL 解決方案按原樣工作。出於此答案的目的,我將假設動態 SQL 如下所示:
DECLARE @sql nvarchar (max) = '', @sqltemplate nvarchar(max) = 'UNION ALL SELECT Column_Name = ''{Column_Name}'', Table_Name = ''{Table_Name}'', Max_Length = MAX(LEN([{Column_Name}])) FROM [oil stop].dbo.[{Table_Name}] '; SELECT @sql += REPLACE( REPLACE( @sqltemplate, '{Column_Name}', Column_Name ), '{Table_Name}', Table_Name ) FROM tempdb.dbo.YourMetaDataTable ; SET @sql = STUFF(@sql, 1, 9, ''); -- remove the leading UNION ALL EXECUTE sp_executesql @sql;
一旦您驗證了腳本正在執行,並確保創建了環回連結伺服器,只需將腳本放入 OPENQUERY 函式中,如下所示:
SELECT * FROM OPENQUERY( YourLinkedServerName, '...' -- the dynamic SQL script ) ;
請記住將腳本中的每個引號(撇號)加倍。
您可能需要進行的另一項重要更改是將 WITH RESULT SETS 子句添加到 EXECUTE 語句以描述結果集,以便 OPENQUERY 可以為您正確處理輸出。在描述結果集時,您可能只是重複在元數據表中為它們定義的相同
Column_Name
類型Table_Name
。對於下面的範例,我假設類型sysname
在這兩種情況下都是。至於Max_Length
專欄,我相信int
在那裡會很好用。因此,修改後的 EXECUTE 語句將如下所示:EXECUTE sp_executesql @sql WITH RESULT SETS ( (Column_Name sysname, Table_Name sysname, Max_Length int) );
為了完整起見,並且為了讓更廣泛的受眾更明顯地看到這個解決方案中缺乏優雅,這就是最終查詢的樣子:
SELECT * FROM OPENQUERY( [OIL STOP], 'DECLARE @sql nvarchar (max) = '''', @sqltemplate nvarchar(max) = ''UNION ALL SELECT Column_Name = ''''{Column_Name}'''', Table_Name = ''''{Table_Name}'''', Max_Length = MAX(LEN([{Column_Name}])) FROM [oil stop].dbo.[{Table_Name}] ''; SELECT @sql += REPLACE( REPLACE( @sqltemplate, ''{Column_Name}'', Column_Name ), ''{Table_Name}'', Table_Name ) FROM tempdb.dbo.MetaData ; SET @sql = STUFF(@sql, 1, 9, ''''); -- remove the leading UNION ALL EXECUTE sp_executesql @sql WITH RESULT SETS ( (Column_Name sysname, Table_Name sysname, Max_Length int) ); ' ) ;
但是,主要問題是上面的查詢仍然無法參數化,這就是我所說的主要限制。即使 OPENQUERY 腳本被指定為字元串文字,它也只能是單個字元串文字——不能是變數,也不能是複雜的表達式。這意味著,如果要將查詢應用於元數據表的不同行子集,則必須為此使用新腳本。
嘗試使用
max(datalength(Column_name))
:SELECT Column_name, table_name, max(datalength(Column_name)) as MaxLength FROM YourTable;