SQL Server: извлечение метаданных таблицы (описание, поля и их типы данных)
Я пытаюсь найти способ извлечения информации о моих таблицах в SQL Server (2008).
Данные, которые мне нужны, должны включать описание таблица (заполняется из свойства Описание В окне Свойства), a список полей таблицы и их типы данных.
есть ли способ извлечь такие метаданные? Я предполагаю, что я должен использовать некоторые sys
sp но я не уверен, какой из них.
14 ответов:
чтобы получить данные описания, вам, к сожалению, придется использовать sysobjects/syscolumns для получения идентификаторов:
SELECT u.name + '.' + t.name AS [table], td.value AS [table_desc], c.name AS [column], cd.value AS [column_desc] FROM sysobjects t INNER JOIN sysusers u ON u.uid = t.uid LEFT OUTER JOIN sys.extended_properties td ON td.major_id = t.id AND td.minor_id = 0 AND td.name = 'MS_Description' INNER JOIN syscolumns c ON c.id = t.id LEFT OUTER JOIN sys.extended_properties cd ON cd.major_id = c.id AND cd.minor_id = c.colid AND cd.name = 'MS_Description' WHERE t.type = 'u' ORDER BY t.name, c.colorder
вы можете сделать это с помощью info-schema, но вам придется объединить etc для вызова OBJECT_ID() - так в чем же смысл?
общие сведения о таблицах и столбцах можно найти в этих таблицах:
select * from INFORMATION_SCHEMA.TABLES select * from INFORMATION_SCHEMA.COLUMNS
описание таблицы является расширенным свойством, вы можете запросить их из sys.extended_properties:
select TableName = tbl.table_schema + '.' + tbl.table_name, TableDescription = prop.value, ColumnName = col.column_name, ColumnDataType = col.data_type FROM information_schema.tables tbl INNER JOIN information_schema.columns col ON col.table_name = tbl.table_name AND col.table_schema = tbl.table_schema LEFT JOIN sys.extended_properties prop ON prop.major_id = object_id(tbl.table_schema + '.' + tbl.table_name) AND prop.minor_id = 0 AND prop.name = 'MS_Description' WHERE tbl.table_type = 'base table'
мне больше всего понравился ответ @Andomar, но мне также нужны были описания столбцов. Вот его запрос изменен, чтобы включить их также. (Раскомментируйте последнюю часть предложения WHERE, чтобы возвращать только строки, где любое описание не является нулевым).
SELECT TableName = tbl.table_schema + '.' + tbl.table_name, TableDescription = tableProp.value, ColumnName = col.column_name, ColumnDataType = col.data_type, ColumnDescription = colDesc.ColumnDescription FROM information_schema.tables tbl INNER JOIN information_schema.columns col ON col.table_name = tbl.table_name LEFT JOIN sys.extended_properties tableProp ON tableProp.major_id = object_id(tbl.table_schema + '.' + tbl.table_name) AND tableProp.minor_id = 0 AND tableProp.name = 'MS_Description' LEFT JOIN ( SELECT sc.object_id, sc.column_id, sc.name, colProp.[value] AS ColumnDescription FROM sys.columns sc INNER JOIN sys.extended_properties colProp ON colProp.major_id = sc.object_id AND colProp.minor_id = sc.column_id AND colProp.name = 'MS_Description' ) colDesc ON colDesc.object_id = object_id(tbl.table_schema + '.' + tbl.table_name) AND colDesc.name = col.COLUMN_NAME WHERE tbl.table_type = 'base table' --AND tableProp.[value] IS NOT NULL OR colDesc.ColumnDescription IS NOT null
Использование Представлений Каталога Объектов:
SELECT T.NAME AS [TABLE NAME], C.NAME AS [COLUMN NAME], P.NAME AS [DATA TYPE], P.MAX_LENGTH AS[SIZE], CAST(P.PRECISION AS VARCHAR) +‘/’+ CAST(P.SCALE AS VARCHAR) AS [PRECISION/SCALE] FROM ADVENTUREWORKS.SYS.OBJECTS AS T JOIN ADVENTUREWORKS.SYS.COLUMNS AS C ON T.OBJECT_ID=C.OBJECT_ID JOIN ADVENTUREWORKS.SYS.TYPES AS P ON C.SYSTEM_TYPE_ID=P.SYSTEM_TYPE_ID WHERE T.TYPE_DESC=‘USER_TABLE’;
Использование Представлений Информационных Схем
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_PRECISION_RADIX, NUMERIC_SCALE, DATETIME_PRECISION FROM ADVENTUREWORKS.INFORMATION_SCHEMA.COLUMNS
Если вы вытягиваете свои запросы с помощью кода java, есть отличный класс, который можно использовать, ResultSetMetaData, который может извлекать имена столбцов и свойства столбцов (тип и длина).
пример
ResultSet rs = null; rs = sql.executeQuery(); if (rs != null) { if (rs.next()) { ResultSetMetaData rsmd = rs.getMetaData(); for (int i = 1; i <= rsmd.getColumnCount(); i++) { System.out.println("column name: " + rsmd.getColumnName(i)); System.out.println("column size: " + rsmd.getColumnDisplaySize(i)); } }
в зависимости от того, сколько метаданных вы хотите, это работает для меня: где может быть все это, как Нортвинд.ДБО.Продукты или просто продукты
SELECT c.name Field, t.name Type, c.Precision, c.Scale, c.is_nullable, c.collation_name FROM sys.columns c INNER JOIN sys.types t ON t.system_type_id=c.system_type_id WHERE object_id=object_id('<table to inspect>') ORDER BY column_id
Я использую этот SQL-код, чтобы получить всю информацию о столбце.
SELECT COL.COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_PRECISION_RADIX, NUMERIC_SCALE, DATETIME_PRECISION, IS_NULLABLE, CONSTRAINT_TYPE, COLUMNPROPERTY(object_id(COL.TABLE_NAME), COL.COLUMN_NAME, 'IsIdentity') IS_IDENTITY, COLUMNPROPERTY(object_id(COL.TABLE_NAME), COL.COLUMN_NAME, 'IsComputed') IS_COMPUTED FROM INFORMATION_SCHEMA.COLUMNS COL LEFT OUTER JOIN ( SELECT COLUMN_NAME, CONSTRAINT_TYPE FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE A INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS B ON A.CONSTRAINT_NAME = B.CONSTRAINT_NAME WHERE A.TABLE_NAME = 'User' ) CONS ON COL.COLUMN_NAME = CONS.COLUMN_NAME WHERE COL.TABLE_NAME = 'User'
Если вы просто хотите просмотреть информацию в удобном виде, подсказка SQL Red Gate может помочь.
при наведении указателя мыши на текст объекта в окне запроса SQL Prompt отобразит текст расширенного свойства MS_Description во всплывающей подсказке. При нажатии на подсказку откроется диалоговое окно, отображающее информацию о столбце, а также DDL объекта.
http://www.red-gate.com/products/sql-development/sql-prompt/
Если это нормально использовать .NET-код, я бы предложил использовать SMO:http://msdn.microsoft.com/en-us/library/ms162169.aspx, в вашем конкретном случае это будет класс таблицыhttp://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.table.aspx Это было бы более портативным решением, чем использование системных представлений и таблиц для конкретных версий.
Если это то, что вы собираетесь использовать на регулярной основе - вы можете написать простой консольное приложение, возможно, с генератором кода времени выполнения T4 http://msdn.microsoft.com/en-us/library/ee844259.aspx
Если это всего лишь одноразовая задача - вы можете использовать мой Livedoco'S( http://www.livedoco.com ) экспорт в XML-функцию с дополнительным преобразованием XSLT или я уверен, что есть бесплатные инструменты, которые могут это сделать. Это выглядит хорошо:http://sqldbdoc.codeplex.com/ - поддерживает XML через XSLT, но я не уверен, что вы можете запустить его для выбор таблиц, хотя (с LiveDoco вы можете).
SELECT sc.name AS ColumnName ,ep.* FROM sys.columns AS sc INNER JOIN sys.extended_properties AS ep ON ep.major_id = sc.[object_id] AND ep.minor_id = sc.column_id WHERE --here put your desired table sc.[object_id] = OBJECT_ID('[Northwind].[dbo].[Products]') -- this is optional, remove this and you get all extended props AND ep.name = 'MS_Description'
select Col.name Columnname,prop.Value Description, tbl.name Tablename, sch.name schemaname from sys.columns col left outer join sys.extended_properties prop on prop.major_id = col.object_id and prop.minor_id = col.column_id inner join sys.tables tbl on col.object_id = tbl.object_id Left outer join sys.schemas sch on sch.schema_id = tbl.schema_id
Я только что закончил библиотеку .net с несколькими полезными запросами, которые возвращают строго типизированные объекты C# для шаблонов кода gen/ t4.
/// <summary> /// Get All Table Names /// </summary> /// <returns></returns> public List<string> GetTableNames() { var sql = @"SELECT name FROM dbo.sysobjects WHERE xtype = 'U' AND name <> 'sysdiagrams' order by name asc"; return databaseWrapper.Call(connection => connection.Query<string>( sql: sql)) .ToList(); } /// <summary> /// Get table info by schema and table or null for all /// </summary> /// <param name="schema"></param> /// <param name="table"></param> /// <returns></returns> public List<SqlTableInfo> GetTableInfo(string schema = null, string table = null) { var result = new List<SqlTableInfo>(); var sql = @"SELECT c.TABLE_CATALOG AS [TableCatalog] , c.TABLE_SCHEMA AS [Schema] , c.TABLE_NAME AS [TableName] , c.COLUMN_NAME AS [ColumnName] , c.ORDINAL_POSITION AS [OrdinalPosition] , c.COLUMN_DEFAULT AS [ColumnDefault] , c.IS_NULLABLE AS [Nullable] , c.DATA_TYPE AS [DataType] , c.CHARACTER_MAXIMUM_LENGTH AS [CharacterMaxLength] , c.CHARACTER_OCTET_LENGTH AS [CharacterOctetLenth] , c.NUMERIC_PRECISION AS [NumericPrecision] , c.NUMERIC_PRECISION_RADIX AS [NumericPrecisionRadix] , c.NUMERIC_SCALE AS [NumericScale] , c.DATETIME_PRECISION AS [DatTimePrecision] , c.CHARACTER_SET_CATALOG AS [CharacterSetCatalog] , c.CHARACTER_SET_SCHEMA AS [CharacterSetSchema] , c.CHARACTER_SET_NAME AS [CharacterSetName] , c.COLLATION_CATALOG AS [CollationCatalog] , c.COLLATION_SCHEMA AS [CollationSchema] , c.COLLATION_NAME AS [CollationName] , c.DOMAIN_CATALOG AS [DomainCatalog] , c.DOMAIN_SCHEMA AS [DomainSchema] , c.DOMAIN_NAME AS [DomainName] , IsPrimaryKey = CONVERT(BIT, (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc , INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME AND tc.TABLE_NAME = c.TABLE_NAME AND cu.TABLE_SCHEMA = c.TABLE_SCHEMA AND cu.COLUMN_NAME = c.COLUMN_NAME) ) , IsIdentity = CONVERT(BIT, (SELECT COUNT(*) FROM sys.objects obj INNER JOIN sys.COLUMNS col ON obj.object_id = col.object_id WHERE obj.type = 'U' AND obj.Name = c.TABLE_NAME AND col.Name = c.COLUMN_NAME AND col.is_identity = 1) ) FROM INFORMATION_SCHEMA.COLUMNS c WHERE (@Schema IS NULL OR c.TABLE_SCHEMA = @Schema) AND (@TableName IS NULL OR c.TABLE_NAME = @TableName) "; var columns = databaseWrapper.Call(connection => connection.Query<SqlColumnInfo>( sql: sql, param: new { Schema = schema, TableName = table }, commandType: CommandType.Text) .ToList()); var refs = this.GetReferentialConstraints(table: table, schema: schema); foreach (var tableName in columns.Select(info => info.TableName).Distinct()) { var tableColumns = columns.Where(info => info.TableName == tableName).ToList(); var children = refs.Where(c => c.UniqueTableName == tableName).ToList(); var parents = refs.Where(c => c.TableName == tableName).ToList(); result.Add(new SqlTableInfo { TableName = tableName, Columns = tableColumns, ChildConstraints = children, ParentConstraints = parents }); } return result; } public List<SqlReferentialConstraint> GetReferentialConstraints(string table = null, string schema = null) { //https://technet.microsoft.com/en-us/library/aa175805%28v=sql.80%29.aspx //https://technet.microsoft.com/en-us/library/Aa175805.312ron1%28l=en-us,v=sql.80%29.jpg //https://msdn.microsoft.com/en-us/library/ms186778.aspx var sql = @" SELECT KCU1.CONSTRAINT_NAME AS [ConstraintName] , KCU1.TABLE_NAME AS [TableName] , KCU1.COLUMN_NAME AS [ColumnName] , KCU2.CONSTRAINT_NAME AS [UniqueConstraintName] , KCU2.TABLE_NAME AS [UniqueTableName] , KCU2.COLUMN_NAME AS [UniqueColumnName] , RC.MATCH_OPTION AS [MatchOption] , RC.UPDATE_RULE AS [UpdateRule] , RC.DELETE_RULE AS [DeleteRule] FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU1 ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2 ON KCU2.CONSTRAINT_CATALOG = RC.UNIQUE_CONSTRAINT_CATALOG AND KCU2.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA AND KCU2.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME WHERE KCU1.ORDINAL_POSITION = KCU2.ORDINAL_POSITION AND (@Table IS NULL OR KCU1.TABLE_NAME = @Table OR KCU2.TABLE_NAME = @Table) AND (@Schema IS NULL OR KCU1.TABLE_SCHEMA = @Schema OR KCU2.TABLE_SCHEMA = @Schema) "; return databaseWrapper.Call(connection => connection.Query<SqlReferentialConstraint>( sql: sql, param: new { Table = table, Schema = schema }, commandType: CommandType.Text)) .ToList(); } /// <summary> /// Get Primary Key Column by schema and table name /// </summary> /// <param name="schema"></param> /// <param name="tableName"></param> /// <returns></returns> public string GetPrimaryKeyColumnName(string schema, string tableName) { var sql = @"SELECT B.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS A , INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE B WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND A.CONSTRAINT_NAME = B.CONSTRAINT_NAME AND A.TABLE_NAME = @TableName AND A.TABLE_SCHEMA = @Schema"; return databaseWrapper.Call(connection => connection.Query<string>( sql: sql, param: new { TableName = tableName, Schema = schema }, commandType: CommandType.Text)) .SingleOrDefault(); } /// <summary> /// Get Identity Column by table name /// </summary> /// <param name="tableName"></param> /// <returns></returns> public string GetIdentityColumnName(string tableName) { var sql = @"SELECT c.Name FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id WHERE o.type = 'U' AND c.is_identity = 1 AND o.Name = @TableName"; return databaseWrapper.Call(connection => connection.Query<string>( sql: sql, param: new { TableName = tableName }, commandType: CommandType.Text)) .SingleOrDefault(); } /// <summary> /// Get All Stored Procedures by schema /// </summary> /// <param name="schema"></param> /// <param name="procName"></param> /// <returns></returns> public List<SqlStoredProcedureInfo> GetStoredProcedureInfo(string schema = null, string procName = null) { var result = new List<SqlStoredProcedureInfo>(); var sql = @"SELECT SPECIFIC_NAME AS [Name] , SPECIFIC_SCHEMA AS [Schema] , Created AS [Created] , LAST_ALTERED AS [LastAltered] FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE' AND (SPECIFIC_SCHEMA = @Schema OR @Schema IS NULL) AND (SPECIFIC_NAME = @ProcName OR @ProcName IS NULL) AND ((SPECIFIC_NAME NOT LIKE 'sp_%' AND SPECIFIC_NAME NOT LIKE 'procUtils_GenerateClass' AND (SPECIFIC_SCHEMA = @Schema OR @Schema IS NULL)) OR SPECIFIC_SCHEMA <> @Schema)"; var sprocs = databaseWrapper.Call(connection => connection.Query<SqlStoredProcedureInfo>( sql: sql, param: new { Schema = schema, ProcName = procName }, commandType: CommandType.Text).ToList()); foreach (var s in sprocs) { s.Parameters = GetStoredProcedureInputParameters(sprocName: s.Name, schema: schema); s.ResultColumns = GetColumnInfoFromStoredProcResult(storedProcName: s.Name, schema: schema); result.Add(s); } return result; } /// <summary> /// Get Column info from Stored procedure result set /// </summary> /// <param name="schema"></param> /// <param name="storedProcName"></param> /// <returns></returns> public List<DataColumn> GetColumnInfoFromStoredProcResult(string schema, string storedProcName) { //this one actually needs to use the dataset because it has the only accurate information about columns and if they can be null or not. var sb = new StringBuilder(); if (!String.IsNullOrEmpty(schema)) { sb.Append(String.Format("exec [{0}].[{1}] ", schema, storedProcName)); } else { sb.Append(String.Format("exec [{0}] ", storedProcName)); } var prms = GetStoredProcedureInputParameters(schema, storedProcName); var count = 1; foreach (var param in prms) { sb.Append(String.Format("{0}=null", param.Name)); if (count < prms.Count) { sb.Append(", "); } count++; } var ds = new DataSet(); using (var sqlConnection = (SqlConnection)databaseWrapper.GetOpenDbConnection()) { using (var sqlAdapter = new SqlDataAdapter(sb.ToString(), sqlConnection)) { if (sqlConnection.State != ConnectionState.Open) sqlConnection.Open(); sqlAdapter.SelectCommand.ExecuteReader(CommandBehavior.SchemaOnly); sqlConnection.Close(); sqlAdapter.FillSchema(ds, SchemaType.Source, "MyTable"); } } var list = new List<DataColumn>(); if (ds.Tables.Count > 0) { list = ds.Tables["MyTable"].Columns.Cast<DataColumn>().ToList(); } return list; } /// <summary> /// Get the input parameters for a stored procedure /// </summary> /// <param name="schema"></param> /// <param name="sprocName"></param> /// <returns></returns> public List<SqlParameterInfo> GetStoredProcedureInputParameters(string schema = null, string sprocName = null) { var sql = @"SELECT SCHEMA_NAME(schema_id) AS [Schema] , P.Name AS Name , @ProcName AS ProcedureName , TYPE_NAME(P.user_type_id) AS [ParameterDataType] , P.max_length AS [MaxLength] , P.Precision AS [Precision] , P.Scale AS Scale , P.has_default_value AS HasDefaultValue , P.default_value AS DefaultValue , P.object_id AS ObjectId , P.parameter_id AS ParameterId , P.system_type_id AS SystemTypeId , P.user_type_id AS UserTypeId , P.is_output AS IsOutput , P.is_cursor_ref AS IsCursor , P.is_xml_document AS IsXmlDocument , P.xml_collection_id AS XmlCollectionId , P.is_readonly AS IsReadOnly FROM sys.objects AS SO INNER JOIN sys.parameters AS P ON SO.object_id = P.object_id WHERE SO.object_id IN (SELECT object_id FROM sys.objects WHERE type IN ('P', 'FN')) AND (SO.Name = @ProcName OR @ProcName IS NULL) AND (SCHEMA_NAME(schema_id) = @Schema OR @Schema IS NULL) ORDER BY P.parameter_id ASC"; var result = databaseWrapper.Call(connection => connection.Query<SqlParameterInfo>( sql: sql, param: new { Schema = schema, ProcName = sprocName }, commandType: CommandType.Text)) .ToList(); return result; }
зацени вот это:
SELECT TABLE_SCHEMA , TABLE_NAME , COLUMN_NAME , ORDINAL_POSITION , COLUMN_DEFAULT , DATA_TYPE , CHARACTER_MAXIMUM_LENGTH , NUMERIC_PRECISION , NUMERIC_PRECISION_RADIX , NUMERIC_SCALE , DATETIME_PRECISION FROM INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA in ('dbo','meta') and table_name in (select name from sys.tables) order by TABLE_SCHEMA , TABLE_NAME ,ORDINAL_POSITION