Sql-Server

使用 Select 語句從同一個表中獲取列名和表名

  • July 31, 2017

我有一個包含 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;

引用自:https://dba.stackexchange.com/questions/137094