J'essaie de trouver un moyen d'extraire des informations sur mes tables dans SQL Server (2008).
Les données dont j'ai besoin doivent inclure la description de la table (renseignée à partir de la propriété Description dans la fenêtre Propriétés), une liste des champs de cette table et leurs types data respectifs.
Est-il possible d'extraire de telles métadonnées? Je suppose que je dois utiliser certains sys
sp mais je ne sais pas lequel.
Pour obtenir les données de description, vous devez malheureusement utiliser sysobjects/syscolumns pour obtenir les identifiants:
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
Vous pouvez le faire avec info-schema, mais vous devez concaténer etc. pour appeler OBJECT_ID () - quel serait donc le but
Des informations génériques sur les tables et les colonnes sont disponibles dans ces tables:
select * from INFORMATION_SCHEMA.TABLES
select * from INFORMATION_SCHEMA.COLUMNS
La description de la table est une propriété étendue, vous pouvez les interroger à partir de 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'
Vous pourriez essayer sp_help <Name of object>
J'ai bien aimé la réponse de @ Andomar, mais j'avais également besoin des descriptions de colonnes. Voici sa requête modifiée pour inclure ceux-ci également. (Supprimez la mise en commentaire de la dernière partie de la clause WHERE pour renvoyer uniquement les lignes contenant l'une ou l'autre des descriptions non nulles).
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
Utilisation des vues du catalogue d'objets:
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’;
Utilisation des vues de schéma d'informations
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
Cela dépend de la quantité de métadonnées que vous souhaitez, cela fonctionne pour moi:
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
Si vous extrayez vos requêtes à l'aide de code Java, il existe une excellente classe, ResultSetMetaData, qui peut extraire les noms de colonne et les propriétés des colonnes (type et longueur).
Exemple
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));
}
}
Le moyen le plus simple d'obtenir un résumé de base de métadonnées consiste à utiliser une table temporaire, puis à utiliser la fonction EXEC:
SELECT * INTO #TempTable FROM TableName
EXEC [tempdb].[dbo].[sp_help] N'#TempTable'
Pour toutes les colonnes du tableau, cela vous donnera le nom de la colonne,
Type de données,
Longueur calculée,
Prec,
Échelle, Nullable,
TrimTrailingBlanks, FixedLenNullInSource, Type de classement
Regarde ça:
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
J'utilise ce code SQL pour obtenir toutes les informations sur une colonne.
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'
Si vous souhaitez simplement afficher les informations de manière pratique, l'invite SQL de Red Gate peut vous aider.
Si vous survolez le texte de l'objet dans une fenêtre de requête, l'invite SQL affiche le texte de la propriété étendue MS_Description dans une info-bulle. En cliquant sur l'info-bulle, une boîte de dialogue contenant les informations sur la colonne et le DDL de l'objet apparaît.
http://www.red-gate.com/products/sql-development/sql-Prompt/
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
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'
Si vous pouvez utiliser du code .NET, je vous conseillerais d'utiliser SMO: http://msdn.Microsoft.com/en-us/library/ms162169.aspx , dans votre cas particulier, il s'agirait de la classe Table. http://msdn.Microsoft.com/en-us/library/Microsoft.sqlserver.management.smo.table.aspx Ce serait une solution plus portable que d'utiliser des vues et des tables système spécifiques à la version.
Si vous souhaitez utiliser ce logiciel régulièrement, vous pouvez écrire une application console simple, avec éventuellement un générateur de code T4 d'exécution http://msdn.Microsoft.com/en-us/library/ee844259. .aspx
S'il ne s'agit que d'une tâche ponctuelle, vous pouvez utiliser la fonctionnalité d'exportation de mon LiveDoco ( http://www.livedoco.com ) avec XML avec une transformation XSLT facultative, ou bien je suis sûr qu'il existe des outils gratuits peut le faire. Celui-ci semble correct: http://sqldbdoc.codeplex.com/ - prend en charge XML via XSLT, mais je ne suis pas sûr que vous puissiez l'exécuter pour une sélection de tables (avec LiveDoco, vous pouvez ).
Je viens de terminer une bibliothèque .net avec quelques requêtes utiles qui renvoient des objets C # fortement typés pour les modèles de code 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;
}