查询以返回所有数据库的数据库,架构,表,列

时间:2019-03-05 01:04:09

标签: sql-server

编辑:我已经编辑了原始帖子,以使内容更加清晰。

1)是否可以编写查询以返回服务器上所有数据库的数据库,架构,表,列和列类型?特别是,是否有可能将sys.databases与其他系统目录视图(例如sys.tables)结合在一起?我无法确定sys.databases与sys.schema,sys.tables或其他系统目录视图之间的PK / FK关系。

2)否则,是否可以编写一个查询来返回上面的查询,在该查询中我将数据库名称作为参数提供,例如使用DB_ID('my_database')作为该查询的过滤器?如果可能的话,我宁愿不使用动态SQL?

3)否则,如果我必须使用动态SQL,是否可以将该动态SQL的结果加载到游标中?

背景:我正在编写一个存储过程,该存储过程为视图生成代码。对于源表中的每个字符列(SP的参数),我需要调用一个删除垃圾字符的函数。我想在实用程序数据库中创建该SP,并支持在多个其他数据库中创建视图。

6 个答案:

答案 0 :(得分:2)

  1. 对于所有数据库:从sys.databases中选择*
  2. 对于所有表:从INFORMATION_SCHEMA.TABLES选择*,其中TABLE_TYPE ='BASE TABLE'
  3. 从所有视图中,从INFORMATION_SCHEMA.TABLES选择*,其中TABLE_TYPE ='VIEW'
  4. 所有列:从INFORMATION_SCHEMA中选择*。请使用table_name作为过滤器。
  5. 在INFORMATION_SCHEMA.COLUMNS表中,您将获得列类型的DATA_TYPE

首先从SQL Server数据库中加载数据库,然后获取数据库名称并连接到该数据库,然后使用上面的所有查询来获取所需的信息。

答案 1 :(得分:1)

我创建了一个存储过程,如果您传递数据库名称,该存储过程可以返回列信息。

Create PROCEDURE SP_GetColumnInfo   
    @DatabaseName varchar(max)
AS
BEGIN   
    SET NOCOUNT ON;
    EXEC('USE ' + @DatabaseName + '; Select DatabaseName = '''+ @DatabaseName +''', Table_Schema, Table_Name, Column_Name, Data_Type from INFORMATION_SCHEMA.COLUMNS as ColumnNames');     
END
GO

答案 2 :(得分:1)

这是对第三个问题的解答,下一种方法将生成一条动态T-SQL语句,该语句将返回您的预期结果。您可以尝试直接执行它或创建一个游标。

-- Declarations
DECLARE @stm nvarchar(max)
SET @stm = N''

-- Dynamic SQL
SELECT @stm = (
   SELECT CONCAT(
        N'UNION ALL ',
        N'SELECT N''',
        name,
        N''' AS DATABASE_NAME, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE '+
        N'FROM ', 
        QUOTENAME([name]), 
        N'.INFORMATION_SCHEMA.COLUMNS '
    )
   FROM sys.databases
   WHERE [name] NOT IN ('master', 'model', 'msdb', 'tempdb')
   FOR XML PATH('')
)
SET @stm = STUFF(@stm, 1, 10, N'')
PRINT @stm

-- Execution without cursor
EXEC sp_executesql @stm

-- Execution with cursor
SET @stm = CONCAT(
    N'DECLARE info CURSOR FORWARD_ONLY READ_ONLY FOR ', 
    @stm
)
EXEC sp_executesql @stm
OPEN info
-- Fetch operations
CLOSE info
DEALLOCATE info

答案 3 :(得分:1)

嘿,所以我也遇到了类似的问题。这是我最终得到的结果,尽管在理想情况下,我想为每个表和列data_type添加row_count。将db添加到架构,表,列信息的答案是函数DB_NAME()

select 
s.name schema_name_,
t.name table_name,
c.name col_name_,
idx.name index_type,
DB_NAME()
from sys.schemas s
join sys.tables t on s.schema_id = t.schema_id
join sys.columns c on t.object_id = c.object_id
left join sys.index_columns ic on c.object_id = ic.object_id and c.column_id = ic.column_id
left join sys.indexes idx on ic.index_id = idx.index_id and ic.object_id = idx.object_id
; 

答案 4 :(得分:0)

所询问的问题没有引用任何先前的努力,没有有效的示例sql。 缺少的是分享这些努力,或者描述问题是什么或收到了什么错误消息。

看看从谷歌返回的第六个(左右)项目

  sqlserver get database, schema, table, column, column type for all databases 

https://www.red-gate.com/simple-talk/sql/database-administration/exploring-your-sql-server-databases-with-t-sql/

在sp_msforeachtable节中引用函数EXEC sp_MSforeachdb'...'

以及“深入研究数据模型”部分,以及清单23:探索列及其数据类型。

根据要求为您的问题提供这些资源。

答案 5 :(得分:0)

基于提供的评论和答案以及我自己的其他研究:

1)不,不可能将sys.database与其他系统目录视图(至少是我需要的视图)(sys.schema,sys.tables,sys.columns)连接。此外,根据我的研究,系统目录视图是特定于数据库的(对于以上视图)。 IOW,sys.tables列出了其数据库中的表,sys.columns列出了其数据库中的列,等等。这包括master数据库。

2)尽管@SMor表示有可能,但我还没有发现不使用动态SQL即可将数据库名称作为参数传递的方法。例如,这不起作用:

SELECT * FROM @database.INFORMATION_SCHEMA.COLUMNS

3)但是,可以使用动态SQL + sys.databases将所需查询生成为UNION ALL查询。 @Zhorov提供了一个很好的例子。也可以使用动态SQL加载游标。同样,@Zhorov提供了一个很好的示例,即将游标声明添加到动态SQL中,然后在下游代码中循环游标。将来,我可能会使用@Zhorov的代码来生成用于构建以下视图的代码。

但是,经过进一步的思考,由于我只需要生成6个左右数据库的视图,我决定“手动”创建一个视图,该视图连接需要使用的数据库:

版本1(用于我的即时需求):

CREATE   VIEW [util].[vwGetColumnInfoISC]
AS
/* Returns column information from selected databases using INFORMATION_SCHEMA views */
WITH cteDeaths
AS (
    SELECT *
      FROM Deaths.INFORMATION_SCHEMA.COLUMNS
),
cteRLDXDth
AS (
    SELECT *
      FROM RLDXDth.INFORMATION_SCHEMA.COLUMNS
),
cteRLDXED
AS (
    SELECT *
      FROM RLDXED.INFORMATION_SCHEMA.COLUMNS
),
cteRLDXHosp
AS (
    SELECT *
      FROM RLDXHosp.INFORMATION_SCHEMA.COLUMNS
),
cteCaped
AS (
    SELECT *
      FROM caped.INFORMATION_SCHEMA.COLUMNS
),
cteHierep
AS (
    SELECT *
      FROM hierep.INFORMATION_SCHEMA.COLUMNS
),
cteUnion
AS (
    SELECT *
      FROM cteDeaths
    UNION ALL
    SELECT *
      FROM cteRLDXDth
    UNION ALL
    SELECT *
      FROM cteRLDXED
    UNION ALL
    SELECT *
      FROM cteRLDXHosp
    UNION ALL
    SELECT *
      FROM cteCaped
    UNION ALL
    SELECT *
      FROM cteHierep
)
SELECT TOP 999999999999999999 *
  FROM cteUnion
ORDER BY
       TABLE_CATALOG
      ,TABLE_SCHEMA
      ,TABLE_NAME
      ,ORDINAL_POSITION
GO

第2版(以供将来使用,尤其是索引信息-我希望以后可以改善此视图以包括更多信息)

CREATE   VIEW [util].[vwGetColumnInfoSYS]
AS
/* Returns column information from selected databases using system catalog views */
WITH cteDeaths
AS (
    SELECT 'Deaths'       AS TABLE_CATALOG
          ,sch.name       AS TABLE_SCHEMA
          ,tbl.name       AS TABLE_NAME
          ,col.name       AS COLUMN_NAME
          ,col.column_id  AS ORDINAL_POSITION
          ,typ.name       AS COLUMN_TYPE
          ,col.max_length AS MAX_LENGTH
          ,col.column_id
          ,col.precision
          ,col.scale
          ,col.collation_name
          ,col.is_nullable
          ,col.is_rowguidcol
          ,col.is_identity
          ,col.is_computed
          ,idx.name       AS index_name
          ,idx.type       AS index_type
          ,idx.type_desc  AS index_description
          ,idx.is_unique
          ,idx.data_space_id
          ,idx.ignore_dup_key
          ,idx.is_primary_key
          ,idx.is_unique_constraint
          ,idx.fill_factor
          ,idx.is_padded
          ,idx.is_disabled
          ,idx.is_hypothetical
          ,idx.allow_row_locks
          ,idx.allow_page_locks
          ,idx.has_filter
          ,idx.filter_definition
          ,idx.compression_delay
          ,ixc.key_ordinal
          ,ixc.partition_ordinal
          ,ixc.is_descending_key
          ,ixc.is_included_column
      FROM Deaths.sys.schemas sch
      JOIN Deaths.sys.tables tbl
        ON sch.schema_id = tbl.schema_id
      JOIN Deaths.sys.columns col
        ON col.object_id = tbl.object_id
      JOIN Deaths.sys.types typ
        ON typ.system_type_id = col.system_type_id
      LEFT JOIN Deaths.sys.index_columns ixc
        ON col.object_id = ixc.object_id
        AND col.column_id = ixc.column_id
      LEFT JOIN Deaths.sys.indexes idx
        ON ixc.object_id = idx.object_id
        AND ixc.index_id = idx.index_id
),
cteRLDXDth
AS (
    SELECT 'RLDXDth'     AS TABLE_CATALOG
          ,sch.name       AS TABLE_SCHEMA
          ,tbl.name       AS TABLE_NAME
          ,col.name       AS COLUMN_NAME
          ,col.column_id  AS ORDINAL_POSITION
          ,typ.name       AS COLUMN_TYPE
          ,col.max_length AS MAX_LENGTH
          ,col.column_id
          ,col.precision
          ,col.scale
          ,col.collation_name
          ,col.is_nullable
          ,col.is_rowguidcol
          ,col.is_identity
          ,col.is_computed
          ,idx.name       AS index_name
          ,idx.type       AS index_type
          ,idx.type_desc  AS index_description
          ,idx.is_unique
          ,idx.data_space_id
          ,idx.ignore_dup_key
          ,idx.is_primary_key
          ,idx.is_unique_constraint
          ,idx.fill_factor
          ,idx.is_padded
          ,idx.is_disabled
          ,idx.is_hypothetical
          ,idx.allow_row_locks
          ,idx.allow_page_locks
          ,idx.has_filter
          ,idx.filter_definition
          ,idx.compression_delay
          ,ixc.key_ordinal
          ,ixc.partition_ordinal
          ,ixc.is_descending_key
          ,ixc.is_included_column
      FROM RLDXDth.sys.schemas sch
      JOIN RLDXDth.sys.tables tbl
        ON sch.schema_id = tbl.schema_id
      JOIN RLDXDth.sys.columns col
        ON col.object_id = tbl.object_id
      JOIN RLDXDth.sys.types typ
        ON typ.system_type_id = col.system_type_id
      LEFT JOIN RLDXDth.sys.index_columns ixc
        ON col.object_id = ixc.object_id
        AND col.column_id = ixc.column_id
      LEFT JOIN RLDXDth.sys.indexes idx
        ON ixc.object_id = idx.object_id
        AND ixc.index_id = idx.index_id
),
cteRLDXED
AS (
    SELECT 'RLDXED'      AS TABLE_CATALOG
          ,sch.name       AS TABLE_SCHEMA
          ,tbl.name       AS TABLE_NAME
          ,col.name       AS COLUMN_NAME
          ,col.column_id  AS ORDINAL_POSITION
          ,typ.name       AS COLUMN_TYPE
          ,col.max_length AS MAX_LENGTH
          ,col.column_id
          ,col.precision
          ,col.scale
          ,col.collation_name
          ,col.is_nullable
          ,col.is_rowguidcol
          ,col.is_identity
          ,col.is_computed
          ,idx.name       AS index_name
          ,idx.type       AS index_type
          ,idx.type_desc  AS index_description
          ,idx.is_unique
          ,idx.data_space_id
          ,idx.ignore_dup_key
          ,idx.is_primary_key
          ,idx.is_unique_constraint
          ,idx.fill_factor
          ,idx.is_padded
          ,idx.is_disabled
          ,idx.is_hypothetical
          ,idx.allow_row_locks
          ,idx.allow_page_locks
          ,idx.has_filter
          ,idx.filter_definition
          ,idx.compression_delay
          ,ixc.key_ordinal
          ,ixc.partition_ordinal
          ,ixc.is_descending_key
          ,ixc.is_included_column
      FROM RLDXED.sys.schemas sch
      JOIN RLDXED.sys.tables tbl
        ON sch.schema_id = tbl.schema_id
      JOIN RLDXED.sys.columns col
        ON col.object_id = tbl.object_id
      JOIN RLDXED.sys.types typ
        ON typ.system_type_id = col.system_type_id
      LEFT JOIN RLDXED.sys.index_columns ixc
        ON col.object_id = ixc.object_id
        AND col.column_id = ixc.column_id
      LEFT JOIN RLDXED.sys.indexes idx
        ON ixc.object_id = idx.object_id
        AND ixc.index_id = idx.index_id
),
cteRLDXHosp
AS (
    SELECT 'RLDXHosp'    AS TABLE_CATALOG
          ,sch.name       AS TABLE_SCHEMA
          ,tbl.name       AS TABLE_NAME
          ,col.name       AS COLUMN_NAME
          ,col.column_id  AS ORDINAL_POSITION
          ,typ.name       AS COLUMN_TYPE
          ,col.max_length AS MAX_LENGTH
          ,col.column_id
          ,col.precision
          ,col.scale
          ,col.collation_name
          ,col.is_nullable
          ,col.is_rowguidcol
          ,col.is_identity
          ,col.is_computed
          ,idx.name       AS index_name
          ,idx.type       AS index_type
          ,idx.type_desc  AS index_description
          ,idx.is_unique
          ,idx.data_space_id
          ,idx.ignore_dup_key
          ,idx.is_primary_key
          ,idx.is_unique_constraint
          ,idx.fill_factor
          ,idx.is_padded
          ,idx.is_disabled
          ,idx.is_hypothetical
          ,idx.allow_row_locks
          ,idx.allow_page_locks
          ,idx.has_filter
          ,idx.filter_definition
          ,idx.compression_delay
          ,ixc.key_ordinal
          ,ixc.partition_ordinal
          ,ixc.is_descending_key
          ,ixc.is_included_column
      FROM RLDXHosp.sys.schemas sch
      JOIN RLDXHosp.sys.tables tbl
        ON sch.schema_id = tbl.schema_id
      JOIN RLDXHosp.sys.columns col
        ON col.object_id = tbl.object_id
      JOIN RLDXHosp.sys.types typ
        ON typ.system_type_id = col.system_type_id
      LEFT JOIN RLDXHosp.sys.index_columns ixc
        ON col.object_id = ixc.object_id
        AND col.column_id = ixc.column_id
      LEFT JOIN RLDXHosp.sys.indexes idx
        ON ixc.object_id = idx.object_id
        AND ixc.index_id = idx.index_id
),
cteCaped
AS (
    SELECT 'caped'       AS TABLE_CATALOG
          ,sch.name       AS TABLE_SCHEMA
          ,tbl.name       AS TABLE_NAME
          ,col.name       AS COLUMN_NAME
          ,col.column_id  AS ORDINAL_POSITION
          ,typ.name       AS COLUMN_TYPE
          ,col.max_length AS MAX_LENGTH
          ,col.column_id
          ,col.precision
          ,col.scale
          ,col.collation_name
          ,col.is_nullable
          ,col.is_rowguidcol
          ,col.is_identity
          ,col.is_computed
          ,idx.name       AS index_name
          ,idx.type       AS index_type
          ,idx.type_desc  AS index_description
          ,idx.is_unique
          ,idx.data_space_id
          ,idx.ignore_dup_key
          ,idx.is_primary_key
          ,idx.is_unique_constraint
          ,idx.fill_factor
          ,idx.is_padded
          ,idx.is_disabled
          ,idx.is_hypothetical
          ,idx.allow_row_locks
          ,idx.allow_page_locks
          ,idx.has_filter
          ,idx.filter_definition
          ,idx.compression_delay
          ,ixc.key_ordinal
          ,ixc.partition_ordinal
          ,ixc.is_descending_key
          ,ixc.is_included_column
      FROM caped.sys.schemas sch
      JOIN caped.sys.tables tbl
        ON sch.schema_id = tbl.schema_id
      JOIN caped.sys.columns col
        ON col.object_id = tbl.object_id
      JOIN caped.sys.types typ
        ON typ.system_type_id = col.system_type_id
      LEFT JOIN caped.sys.index_columns ixc
        ON col.object_id = ixc.object_id
        AND col.column_id = ixc.column_id
      LEFT JOIN caped.sys.indexes idx
        ON ixc.object_id = idx.object_id
        AND ixc.index_id = idx.index_id
),
cteHierep
AS (
    SELECT 'hierep'      AS TABLE_CATALOG
          ,sch.name       AS TABLE_SCHEMA
          ,tbl.name       AS TABLE_NAME
          ,col.name       AS COLUMN_NAME
          ,col.column_id  AS ORDINAL_POSITION
          ,typ.name       AS COLUMN_TYPE
          ,col.max_length AS MAX_LENGTH
          ,col.column_id
          ,col.precision
          ,col.scale
          ,col.collation_name
          ,col.is_nullable
          ,col.is_rowguidcol
          ,col.is_identity
          ,col.is_computed
          ,idx.name       AS index_name
          ,idx.type       AS index_type
          ,idx.type_desc  AS index_description
          ,idx.is_unique
          ,idx.data_space_id
          ,idx.ignore_dup_key
          ,idx.is_primary_key
          ,idx.is_unique_constraint
          ,idx.fill_factor
          ,idx.is_padded
          ,idx.is_disabled
          ,idx.is_hypothetical
          ,idx.allow_row_locks
          ,idx.allow_page_locks
          ,idx.has_filter
          ,idx.filter_definition
          ,idx.compression_delay
          ,ixc.key_ordinal
          ,ixc.partition_ordinal
          ,ixc.is_descending_key
          ,ixc.is_included_column
      FROM hierep.sys.schemas sch
      JOIN hierep.sys.tables tbl
        ON sch.schema_id = tbl.schema_id
      JOIN hierep.sys.columns col
        ON col.object_id = tbl.object_id
      JOIN hierep.sys.types typ
        ON typ.system_type_id = col.system_type_id
      LEFT JOIN hierep.sys.index_columns ixc
        ON col.object_id = ixc.object_id
        AND col.column_id = ixc.column_id
      LEFT JOIN hierep.sys.indexes idx
        ON ixc.object_id = idx.object_id
        AND ixc.index_id = idx.index_id
),
cteUnion
AS (
    SELECT *
      FROM cteDeaths
    UNION ALL
    SELECT *
      FROM cteRLDXDth
    UNION ALL
    SELECT *
      FROM cteRLDXED
    UNION ALL
    SELECT *
      FROM cteRLDXHosp
    UNION ALL
    SELECT *
      FROM cteCaped
    UNION ALL
    SELECT *
      FROM cteHierep
)
SELECT TOP 999999999999999999 *
  FROM cteUnion
ORDER BY
       TABLE_CATALOG
      ,TABLE_SCHEMA
      ,TABLE_NAME
      ,ORDINAL_POSITION
GO

我希望SQL Server开箱即用地提供这样的总体视图,这是我最初提出的要点。

最后,我编写了一个代码生成器来生成所需的视图:

(有关PatExclude8K的信息,请参见http://www.sqlservercentral.com/scripts/T-SQL/117890/):

CREATE PROCEDURE [dbo].[spGenerateCleanViews2]
    @srcTableName SYSNAME  -- Must be a 3-level table name, case-insensitive
   ,@tgtTableName SYSNAME = 'cln.vw{srcTable}'
   ,@debug BIT = 1
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Declare variables
    DECLARE @srcDatabase SYSNAME
           ,@srcSchema SYSNAME
           ,@srcTable SYSNAME
           ,@tgtDatabase SYSNAME
           ,@tgtSchema SYSNAME
           ,@tgtTable SYSNAME
    ;

    DECLARE @columnName SYSNAME
           ,@columnType SYSNAME
           ,@sql NVARCHAR(MAX) = ''
           ,@DBExec NVARCHAR(100)
           ,@line NVARCHAR(256)
           ,@n INT
           ,@pattern VARCHAR(100) = '%[^ -~]%'  -- Low order ASCII print characters CHAR(32) - CHAR(126)
    ;

    -- Parse source table
    SET @srcTable = PARSENAME(@srcTableName,1);
    SET @srcSchema = PARSENAME(@srcTableName,2);
    SET @srcDatabase = PARSENAME(@srcTableName,3);

    -- Don't try to set defaults - if it's not a three level name then abort
    IF @srcTable IS NULL
        OR @srcSchema IS NULL
        OR @srcDatabase IS NULL
    BEGIN
        RAISERROR ('A three-level table name (server.schema.table) is required.',16,1);
        RETURN;
    END

    -- Parse target table
    SET @tgtTable = PARSENAME(@tgtTableName,1);
    SET @tgtSchema = PARSENAME(@tgtTableName,2);
    SET @tgtDatabase = PARSENAME(@tgtTableName,3);

    -- Set defaults if NULL
    IF @tgtDatabase IS NULL
        SET @tgtDatabase = DB_NAME()

    IF @tgtSchema IS NULL
        SET @tgtSchema = 'cln'

    IF @tgtTable IS NULL
        SET @tgtTable = 'vw{srcTable}'

    -- Replace tokens in the target table name
    SET @tgtTable = REPLACE(@tgtTable,'{srcTable}',@srcTable);

    -- Create scrollable cursor
    BEGIN TRY
        DECLARE cursorColumns SCROLL CURSOR FOR SELECT COLUMN_NAME
                                                      ,DATA_TYPE
                                                      ,ORDINAL_POSITION
          FROM util.vwGetColumnInfoISC
         WHERE TABLE_CATALOG = @srcDatabase COLLATE Latin1_General_100_CI_AI
           AND TABLE_SCHEMA = @srcSchema COLLATE Latin1_General_100_CI_AI
           AND TABLE_NAME = @srcTable COLLATE Latin1_General_100_CI_AI
        ORDER BY
               ORDINAL_POSITION
    END TRY
    BEGIN CATCH
        DEALLOCATE cursorColumns;
        DECLARE cursorColumns SCROLL CURSOR FOR SELECT COLUMN_NAME
                                                      ,DATA_TYPE
                                                      ,ORDINAL_POSITION
          FROM util.vwGetColumnInfoISC
         WHERE TABLE_CATALOG = @srcDatabase COLLATE Latin1_General_100_CI_AI
           AND TABLE_SCHEMA = @srcSchema COLLATE Latin1_General_100_CI_AI
           AND TABLE_NAME = @srcTable COLLATE Latin1_General_100_CI_AI
        ORDER BY
               ORDINAL_POSITION
    END CATCH

    OPEN cursorColumns;

    FETCH FIRST FROM cursorColumns INTO @columnName,@columnType,@n;
    WHILE @@fetch_status = 0
    BEGIN
    SET @line = REPLICATE(' ',256);
    IF @columnType LIKE '%char'
    BEGIN
        SET @line = STUFF(@line,7,50,',LTRIM(RTRIM([t{alias}].[NewString]))');  -- strip leading and trailing spaces
        SET @line = REPLACE(@line,'{alias}',FORMAT(@n,'00'));
        SET @line = STUFF(@line,100,50,'AS {columnName}');
        SET @line = REPLACE(@line,'{columnName}',QUOTENAME(@columnName,'['))
    END
    ELSE
    BEGIN
        SET @line = STUFF(@line,7,50,',[src].{columnName}');
        SET @line = REPLACE(@line,'{columnName}',QUOTENAME(@columnName,'['))
        SET @line = STUFF(@line,100,50,'AS {columnName}');
        SET @line = REPLACE(@line,'{columnName}',QUOTENAME(@columnName,'['))
    END
    SET @sql += RTRIM(@line) + CHAR(13);
    FETCH NEXT FROM cursorColumns INTO @columnName,@columnType,@n;
    END

    -- Source Table
    -- Note: If the source table is in a different database than the target database then a synonym must be created!
    SET @line = REPLICATE(' ',256);
    SET @line = STUFF(@line,3,50,'FROM {srcSchema}.{srcTable} src');
    SET @sql += RTRIM(@line) + CHAR(13);

    -- Cross Apply
    FETCH FIRST FROM cursorColumns INTO @columnName,@columnType,@n;
    WHILE @@fetch_status = 0
    BEGIN
    SET @line = REPLICATE(' ',256);
    IF @columnType LIKE '%char'
    BEGIN
        SET @line = STUFF(@line,3,60,'CROSS APPLY dbo.fnPatExclude8K_Table([src].{columnName},''{pattern}'') t{alias}');
        SET @line = REPLACE(REPLACE(REPLACE(@line,'{columnName}',QUOTENAME(@columnName,'[')),'{alias}',FORMAT(@n,'00')),'{pattern}',@pattern);
        SET @sql += RTRIM(@line) + CHAR(13);
    END
    FETCH NEXT FROM cursorColumns INTO @columnName,@columnType,@n;
    END

    CLOSE cursorColumns;
    DEALLOCATE cursorColumns;

    SET @sql = STUFF(@sql,1,7,'SELECT ');

    -- Do not indent the following code block
    SET @sql =
'CREATE OR ALTER VIEW {tgtSchema}.{tgtTable}
AS
' + @sql
;

    SET @sql = REPLACE(@sql,'{srcSchema}',QUOTENAME(@srcSchema,'['));
    SET @sql = REPLACE(@sql,'{srcTable}',QUOTENAME(@srcTable,'['));
    SET @sql = REPLACE(@sql,'{tgtDatabase}',QUOTENAME(@tgtDatabase,'['));
    SET @sql = REPLACE(@sql,'{tgtSchema}',QUOTENAME(@tgtSchema,'['));
    SET @sql = REPLACE(@sql,'{tgtTable}',QUOTENAME(@tgtTable,'['));

    -- If debugging display generated code
    -- XML is used to overcome the 4000 character limit of PRINT
    IF @debug = 1
        SELECT CAST('<![CDATA[' + @sql + ']]>' AS XML);
    ELSE
    BEGIN
        -- Set execution context
        SET @DBExec = @tgtDatabase + N'.sys.sp_executesql';
        EXEC @DBExec @sql;
    END
END
GO