编辑:我已经编辑了原始帖子,以使内容更加清晰。
1)是否可以编写查询以返回服务器上所有数据库的数据库,架构,表,列和列类型?特别是,是否有可能将sys.databases与其他系统目录视图(例如sys.tables)结合在一起?我无法确定sys.databases与sys.schema,sys.tables或其他系统目录视图之间的PK / FK关系。
2)否则,是否可以编写一个查询来返回上面的查询,在该查询中我将数据库名称作为参数提供,例如使用DB_ID('my_database')作为该查询的过滤器?如果可能的话,我宁愿不使用动态SQL?
3)否则,如果我必须使用动态SQL,是否可以将该动态SQL的结果加载到游标中?
背景:我正在编写一个存储过程,该存储过程为视图生成代码。对于源表中的每个字符列(SP的参数),我需要调用一个删除垃圾字符的函数。我想在实用程序数据库中创建该SP,并支持在多个其他数据库中创建视图。
答案 0 :(得分:2)
首先从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
在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