尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

SQL Server 2019元数据查询实战:从sys视图到数据库字典生成

SQL Server 2019元数据查询实战:从sys视图到数据库字典生成 1. 项目概述从一次“无效对象名”报错说起那天下午我正在为一个新接手的项目梳理数据库文档。项目用的是 SQL Server 2019我需要快速摸清整个实例下有哪些数据库每个库里有什么表表结构如何主键是谁。这听起来是个基础活对吧我熟练地打开 SQL Server Management Studio (SSMS)准备查询系统视图。我敲下了类似SELECT * FROM user_tab_columns的语句想看看表字段信息结果迎头就是一盆冷水——SSMS 毫不客气地抛出一个错误“对象名 ‘user_tab_columns’ 无效”。我愣了一下随即反应过来这是把 Oracle 的习惯带到 SQL Server 来了。USER_TAB_COLUMNS和USER_CONS_COLUMNS是 Oracle 数据库的系统视图在 SQL Server 的世界里这套命名规则完全不适用。这个看似简单的报错恰恰是很多从 Oracle 转向 SQL Server或者初学数据库元数据查询的朋友最容易踩的坑。它背后反映的是不同数据库管理系统DBMS在架构和系统目录设计上的根本差异。本次分享我就以 SQL Server 2019 为环境从头到尾演示如何正确、高效地查询我们关心的所有元数据信息——数据库名、表名、表结构、字段乃至主键并彻底厘清那些“无效对象名”背后的原因与正确的替代方案。无论你是需要做数据字典、进行数据迁移评估还是单纯想了解数据库资产这套方法都能让你事半功倍。2. 核心思路解析理解 SQL Server 的系统信息架构在动手写查询之前我们必须先理解 SQL Server 是如何组织和管理这些元数据的。与 Oracle 使用一系列以USER_、ALL_、DBA_为前缀的视图不同SQL Server 提供了一套更为精细和标准的系统目录视图Catalog Views和信息架构视图Information Schema Views。这是两种官方推荐的查询方式它们位于不同的架构Schema下视角略有不同。2.1 两种主流的元数据查询途径1. 系统目录视图 (sys.*)这是 SQL Server 最核心、最底层的元数据视图位于sys架构下。它们直接反映了数据库引擎内部的存储结构信息最全、最详细但结构也相对复杂表与表之间关联较多。例如sys.databases存储所有数据库信息sys.tables存储所有用户表信息sys.columns存储所有列信息。2. 信息架构视图 (INFORMATION_SCHEMA.*)这是一组遵循 SQL 标准ISO/IEC 9075的视图位于INFORMATION_SCHEMA架构下。它们是为了跨不同数据库系统如 SQL Server, MySQL, PostgreSQL提供一致的查询接口而设计的因此通用性更好但可能不包含某些 SQL Server 特有的属性。例如INFORMATION_SCHEMA.TABLES可以查询表信息INFORMATION_SCHEMA.COLUMNS可以查询列信息。注意对于“查询所有数据库名”这个需求INFORMATION_SCHEMA视图是无法直接满足的因为它们是数据库级别的视图每个数据库都有自己的INFORMATION_SCHEMA。要跨实例查询数据库列表必须使用sys.databases。2.2 为何USER_TAB_COLUMNS会无效这是一个关键的知识点。在 Oracle 中USER_TAB_COLUMNS显示当前用户拥有的所有表的列信息。ALL_TAB_COLUMNS显示当前用户有权限访问的所有表的列信息。DBA_TAB_COLUMNS显示数据库中所有表的列信息需要 DBA 权限。这些视图是 Oracle 数据字典的核心部分。而在 SQL Server 中根本没有这些对象。SQL Server 使用完全不同的系统对象来存储元数据。试图调用USER_TAB_COLUMNSSQL Server 自然会在当前数据库和master数据库的sys架构下都找不到这个对象从而报错“对象名无效”。正确的替代方案是替代USER_TAB_COLUMNS使用sys.columns结合sys.tables和sys.schemas或者使用INFORMATION_SCHEMA.COLUMNS。替代USER_CONS_COLUMNS使用sys.key_constraints、sys.index_columns等视图来查询主键约束信息。理解了这些基础我们就能避免张冠李戴写出正确的查询语句。3. 逐项实战查询所有核心元数据接下来我们进入实战环节。我会分步骤展示如何查询每一项信息并提供最常用、最清晰的 SQL 语句。假设我们的 SQL Server 2019 实例上有多个数据库我们需要一个全局视角。3.1 查询实例中所有数据库名这是唯一一个必须从实例层面master数据库上下文进行的查询。-- 方法1使用 sys.databases最常用信息最全 USE master; GO SELECT name AS DatabaseName, database_id AS DBID, create_date, state_desc AS [State], user_access_desc AS [UserAccess], recovery_model_desc AS RecoveryModel FROM sys.databases WHERE name NOT IN (master, tempdb, model, msdb) -- 过滤掉系统数据库 ORDER BY name;-- 方法2使用 sp_databases 存储过程简单但输出格式固定 EXEC sp_databases;实操心得sys.databases视图提供了极其丰富的数据库属性如兼容性级别、排序规则、是否已加密等。在自动化脚本中我通常使用sys.databases因为它返回的结果集更结构化便于后续处理。sp_databases更适合在 SSMS 里快速看一眼。3.2 查询指定数据库中的所有表名我们需要切换到目标数据库或者使用三部分名称DatabaseName.sys.tables来查询。-- 假设我们要查询名为 ‘YourDatabaseName‘ 的数据库中的表 USE YourDatabaseName; GO -- 方法1使用 sys.tables推荐 SELECT s.name AS SchemaName, t.name AS TableName, t.create_date, t.modify_date, t.type_desc AS ObjectType -- 通常是 ‘USER_TABLE‘ FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id s.schema_id ORDER BY s.name, t.name;-- 方法2使用 INFORMATION_SCHEMA.TABLES SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE ‘BASE TABLE‘ -- 确保只查询用户表排除视图 ORDER BY TABLE_SCHEMA, TABLE_NAME;注意事项sys.tables只包含用户表。如果你需要查看所有对象包括视图、同义词等应使用sys.objects并过滤type ‘U‘用户表。INFORMATION_SCHEMA.TABLES中的TABLE_TYPE字段可以区分 ‘BASE TABLE‘ 和 ‘VIEW‘。3.3 查询指定表的表结构字段信息这是替代USER_TAB_COLUMNS的核心操作。-- 目标查询数据库 ‘YourDatabaseName‘ 中架构为 ‘dbo‘表名为 ‘YourTableName‘ 的所有字段信息 USE YourDatabaseName; GO -- 方法1使用 sys.columns功能最强大 SELECT s.name AS SchemaName, t.name AS TableName, c.name AS ColumnName, ty.name AS DataType, c.max_length AS MaxLength, c.precision, c.scale, c.is_nullable AS IsNullable, c.is_identity AS IsIdentity, c.default_object_id AS HasDefault, ep.value AS ColumnDescription -- 扩展属性如字段注释 FROM sys.columns c INNER JOIN sys.tables t ON c.object_id t.object_id INNER JOIN sys.schemas s ON t.schema_id s.schema_id INNER JOIN sys.types ty ON c.user_type_id ty.user_type_id LEFT JOIN sys.extended_properties ep ON c.object_id ep.major_id AND c.column_id ep.minor_id AND ep.name ‘MS_Description‘ -- 获取MS_Description格式的注释 WHERE s.name ‘dbo‘ AND t.name ‘YourTableName‘ ORDER BY c.column_id; -- 按列的顺序ID排序-- 方法2使用 INFORMATION_SCHEMA.COLUMNS跨数据库兼容 SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, IS_NULLABLE, COLUMN_DEFAULT, ORDINAL_POSITION FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA ‘dbo‘ AND TABLE_NAME ‘YourTableName‘ ORDER BY ORDINAL_POSITION;核心细节解析数据类型sys.types视图提供了完整的数据类型名称。sys.columns中的system_type_id和user_type_id需要关联此视图来获取可读的名称。扩展属性SQL Server 中字段或表的注释通常存储在sys.extended_properties中其中name‘MS_Description‘是 SSMS 默认使用的属性名。通过左连接LEFT JOIN可以获取到这些注释信息这对于生成数据字典至关重要。列顺序column_id或ORDINAL_POSITION代表了列在表中的物理定义顺序按此排序可以还原出真实的表结构。3.4 查询指定表的主键信息这是替代USER_CONS_COLUMNS和查询约束信息的核心操作。主键在 SQL Server 中是一种特殊的约束Constraint类型为 ‘PK‘。-- 查询表 ‘YourTableName‘ 的主键约束及构成列 USE YourDatabaseName; GO SELECT s.name AS SchemaName, t.name AS TableName, kc.name AS PrimaryKeyName, c.name AS ColumnName, ic.key_ordinal AS KeyOrder -- 列在主键中的顺序针对复合主键 FROM sys.key_constraints kc -- 专门用于主键、唯一键约束 INNER JOIN sys.tables t ON kc.parent_object_id t.object_id INNER JOIN sys.schemas s ON t.schema_id s.schema_id INNER JOIN sys.index_columns ic ON kc.parent_object_id ic.object_id AND kc.unique_index_id ic.index_id INNER JOIN sys.columns c ON ic.object_id c.object_id AND ic.column_id c.column_id WHERE kc.type ‘PK‘ -- 筛选主键约束 AND s.name ‘dbo‘ AND t.name ‘YourTableName‘ ORDER BY ic.key_ordinal; -- 按主键列顺序排序原理解读sys.key_constraints存储了所有主键‘PK‘和唯一键‘UQ‘约束。主键约束必然对应一个唯一索引。unique_index_id字段关联到sys.indexes。sys.index_columns存储了索引中包含的列及其顺序。通过关联此视图我们可以知道主键由哪些列组成以及这些列的顺序对于复合主键非常重要。最后关联sys.columns获取列的名称。常见问题如果查询结果为空可能有三种情况① 表名或架构名写错② 该表确实没有定义主键③ 查询上下文不在正确的数据库中。务必先确认前两点。4. 整合与进阶一键生成数据库字典脚本在实际工作中我们往往需要一份完整的报告。我们可以将上述查询整合起来甚至编写一个存储过程遍历所有用户数据库和表生成一份全面的数据字典。下面是一个简化版的整合脚本示例它会在当前连接的实例上为每个用户数据库生成一个汇总视图-- 创建一个临时表来存储最终结果 IF OBJECT_ID(‘tempdb..#DatabaseDictionary‘) IS NOT NULL DROP TABLE #DatabaseDictionary; CREATE TABLE #DatabaseDictionary ( DatabaseName sysname, SchemaName sysname, TableName sysname, ColumnName sysname, DataType nvarchar(128), MaxLength smallint, IsNullable varchar(3), IsIdentity varchar(3), PrimaryKeyFlag varchar(3), ColumnDescription nvarchar(4000) ); -- 声明游标遍历所有用户数据库 DECLARE dbname sysname; DECLARE db_cursor CURSOR FOR SELECT name FROM sys.databases WHERE state_desc ‘ONLINE‘ AND name NOT IN (‘master‘, ‘tempdb‘, ‘model‘, ‘msdb‘) AND is_read_only 0; -- 排除只读数据库 OPEN db_cursor; FETCH NEXT FROM db_cursor INTO dbname; WHILE FETCH_STATUS 0 BEGIN DECLARE sql nvarchar(MAX); -- 动态构建SQL插入到临时表 SET sql N‘ USE [‘ dbname N‘]; INSERT INTO #DatabaseDictionary SELECT DB_NAME() AS DatabaseName, sch.name AS SchemaName, tb.name AS TableName, col.name AS ColumnName, ty.name AS DataType, col.max_length AS MaxLength, CASE col.is_nullable WHEN 1 THEN ‘‘YES‘‘ ELSE ‘‘NO‘‘ END AS IsNullable, CASE col.is_identity WHEN 1 THEN ‘‘YES‘‘ ELSE ‘‘NO‘‘ END AS IsIdentity, CASE WHEN pk.column_id IS NOT NULL THEN ‘‘YES‘‘ ELSE ‘‘NO‘‘ END AS PrimaryKeyFlag, ep.value AS ColumnDescription FROM sys.columns col INNER JOIN sys.tables tb ON col.object_id tb.object_id INNER JOIN sys.schemas sch ON tb.schema_id sch.schema_id INNER JOIN sys.types ty ON col.user_type_id ty.user_type_id LEFT JOIN ( SELECT ic.object_id, ic.column_id FROM sys.index_columns ic INNER JOIN sys.key_constraints kc ON ic.object_id kc.parent_object_id AND ic.index_id kc.unique_index_id WHERE kc.type ‘‘PK‘‘ ) pk ON col.object_id pk.object_id AND col.column_id pk.column_id LEFT JOIN sys.extended_properties ep ON col.object_id ep.major_id AND col.column_id ep.minor_id AND ep.name ‘‘MS_Description‘‘ WHERE tb.is_ms_shipped 0; -- 排除系统表 ‘; EXEC sp_executesql sql; PRINT ‘已处理数据库: ‘ dbname; FETCH NEXT FROM db_cursor INTO dbname; END; CLOSE db_cursor; DEALLOCATE db_cursor; -- 查看结果 SELECT * FROM #DatabaseDictionary ORDER BY DatabaseName, SchemaName, TableName, ColumnName;脚本解读与避坑技巧使用游标为了跨多个数据库执行查询我们使用了游标来动态切换数据库上下文。这是 SQL Server 中处理此类跨库操作的常见模式。动态 SQLsp_executesql用于执行动态构建的 SQL 字符串。注意字符串中的数据库名 ([ dbname ]) 使用了方括号这是为了避免数据库名中包含特殊字符如空格、横线导致语法错误。排除系统对象tb.is_ms_shipped 0这个条件非常重要它能过滤掉 SQL Server 自带的系统表确保结果集中只包含用户创建的表。主键判断逻辑我们使用了一个子查询来关联主键信息。如果某列存在于主键索引的列列表中则标记为 ‘YES‘。这是一个高效的判断方法。性能考虑在数据库非常多、表结构极其庞大的生产环境中此脚本可能会运行较长时间并消耗一定资源。建议在业务低峰期执行或者针对特定数据库进行过滤。5. 常见问题排查与解决方案实录即使掌握了正确的方法在实际操作中仍可能遇到各种问题。下面是我总结的几个典型场景及其解决方案。5.1 执行查询时权限不足问题描述执行sys或INFORMATION_SCHEMA视图查询时提示“拒绝了对对象 ‘xxx‘ 的 SELECT 权限”。原因分析SQL Server 的安全性模型要求用户对底层系统视图有相应的权限。虽然这些视图通常对public角色有 SELECT 权限但在某些严格的权限设置下或当使用非特权账户时可能会遇到此问题。解决方案使用具有足够权限的账户登录如sa或具有sysadmin服务器角色的账户。授予特定权限如果无法使用高权限账户可以请管理员为你的用户账户授予必要的权限。-- 授予对某个特定数据库的系统视图的查看定义权限通常足够用于查询 USE YourDatabaseName; GRANT VIEW DEFINITION TO [YourUserName]; -- 或者授予对所有数据库的该权限在master数据库执行 USE master; GRANT VIEW ANY DEFINITION TO [YourUserName];注意VIEW DEFINITION是一个相对宽松的权限允许用户查看元数据但不一定允许修改数据。在生产环境中授权需谨慎。5.2 查询结果不包含注释MS_Description问题描述按照上述脚本查询ColumnDescription字段大部分为 NULL。原因分析注释信息是通过sys.extended_properties存储的。如果表或字段在设计时没有通过 SSMS 的属性窗口或sp_addextendedproperty存储过程添加描述那么该字段自然为 NULL。解决方案事后添加注释可以使用以下命令为表和字段添加注释。-- 为表添加注释 EXEC sys.sp_addextendedproperty name N‘MS_Description‘, value N‘这是一张用户信息表‘, level0type N‘SCHEMA‘, level0name N‘dbo‘, level1type N‘TABLE‘, level1name N‘YourTableName‘; -- 为字段添加注释 EXEC sys.sp_addextendedproperty name N‘MS_Description‘, value N‘用户的唯一标识符‘, level0type N‘SCHEMA‘, level0name N‘dbo‘, level1type N‘TABLE‘, level1name N‘YourTableName‘, level2type N‘COLUMN‘, level2name N‘UserID‘;使用第三方工具许多数据库设计工具如 Redgate SQL Prompt, ApexSQL Doc或 ER 工具在生成 DDL 时会自动包含扩展属性。5.3 查询复合主键时顺序错误问题描述对于由多个字段组成的复合主键查询出来的列顺序与定义顺序不符。原因排查问题通常出在关联sys.index_columns视图时没有按照key_ordinal字段排序。key_ordinal的值从 1 开始精确表示了该列在索引键中的位置。解决方案确保在最终查询的ORDER BY子句中包含key_ordinal。正如我在 3.4 节的示例脚本中所做的那样ORDER BY ic.key_ordinal。这样就能确保输出结果中主键列的顺序与定义完全一致。5.4 在 Azure SQL Database 中的差异问题描述在 Azure SQL Database云托管数据库中某些系统视图或方法可能不可用或行为不同。差异点与解决方案查询所有数据库在 Azure SQL Database 的单数据库或弹性池服务层级你通常只能访问当前连接的数据库无法查询服务器上的所有数据库列表。这是出于安全和多租户隔离的设计。如果需要跨数据库信息可能需要使用 Azure SQL 托管实例或者通过 Azure 门户、PowerShell、CLI 或管理 API 来获取。部分动态管理视图DMV受限一些与服务器级配置相关的sys视图可能返回空值或受限信息。通用建议对于数据库内的元数据查询如表、列、主键本文介绍的sys和INFORMATION_SCHEMA视图在 Azure SQL Database 中完全适用可以放心使用。6. 工具推荐与效率提升除了手写 SQL合理利用工具能极大提升效率。1. SQL Server Management Studio (SSMS) 对象资源管理器最直观的方式。展开数据库→表右键点击表选择“设计”或“编写表脚本为”→“CREATE 到”→“新查询编辑器窗口”即可生成包含表结构甚至包含主键、索引的完整 SQL 脚本。对于单表查看非常方便。2. 生成脚本向导在 SSMS 中右键点击数据库 - “任务” - “生成脚本”。按照向导可以选择特定对象如表并高级设置中勾选“编写主键、外键、唯一键和索引的脚本”可以批量生成整个数据库或特定对象的创建脚本其中就包含了完整的结构信息。3. 第三方数据库工具dbForge Studio for SQL Server / ApexSQL DevTool这些专业工具提供了更强大的对象浏览器和数据字典生成功能通常能以更友好的格式如 HTML、Excel、Markdown导出文档。DBeaver一个免费开源的通用数据库工具支持 SQL Server。它的元数据浏览器也很强大并且可以生成 ER 图。4. PowerShell dbatools 模块对于需要自动化、定期生成数据库架构文档的运维场景PowerShell 是绝佳选择。dbatools是一个强大的社区模块。# 安装 dbatools 模块如果未安装 Install-Module -Name dbatools -Force # 导出指定SQL Server实例上所有数据库的表结构到文件 Export-DbaScript -SqlInstance YourServerName -Path C:\DBA\SchemaScripts\ -ScriptOptions { ScriptSchema $true; ScriptData $false }这个命令会为每个数据库生成一个.sql文件里面是所有对象的创建脚本包括表结构、主键、约束等。从一次“无效对象名”的错误出发我们系统地梳理了在 SQL Server 2019 中查询数据库元数据的正确姿势。核心在于摒弃其他数据库的固有习惯转而深入理解 SQL Server 独有的sys系统目录视图和标准的INFORMATION_SCHEMA视图。通过组合查询sys.databases、sys.tables、sys.columns、sys.key_constraints和sys.index_columns等视图我们可以精准地获取从数据库列表到字段注释的所有信息。在实战中注意权限、注释的存储方式以及复合主键的列顺序等细节能让你避免很多坑。最后无论是整合脚本进行批量处理还是借助 SSMS 向导、PowerShell 等工具提升效率目的都是将枯燥的元数据查询变成一项可管理、可自动化的常规任务为数据库管理、文档编写和数据治理打下坚实的基础。
返回列表