2017-02-15 118 views
1

到目前爲止我發現的其他東西都只是指向sys.columns並返回關於列的一些元數據。但是,我想以可用於動態SQL的格式在另一個表中創建相同列的信息。如何獲取SQL Server中列的數據類型?

我遇到的主要問題是,對於不允許列寬的int或bit等類型,sys.columns仍然顯示長度,精度或縮放比例(全部爲3約會時間)。

是否有某種方法從列元數據中獲取可用類型?例如,在給定列名,我期望的結果早在intdecimal(5,2)

回答

1

從路易·戴維森這裏偷竊:Utility Queries–Column Metadata - Louis Davidson

SELECT * 
FROM (SELECT REPLACE(LOWER(objects.type_desc), '_', ' ') AS table_type, schemas.name AS schema_name, objects.name AS table_name, 
        columns.name AS column_name, CASE WHEN columns.is_identity = 1 THEN 'IDENTITY NOT NULL' 
                 WHEN columns.is_nullable = 1 THEN 'NULL' 
                 ELSE 'NOT NULL' 
               END AS nullability, 
        --types that have a ascii character or binary length 
        CASE WHEN columns.is_computed = 1 THEN 'Computed' 
         WHEN types.name IN ('varchar', 'char', 'varbinary') THEN types.name + 
             CASE WHEN columns.max_length = -1 THEN '(max)'  
               ELSE '(' + CAST(columns.max_length AS VARCHAR(4)) + ')' END  
         --types that have an unicode character type that requires length to be halved 
         WHEN types.name IN ('nvarchar', 'nchar') THEN types.name + 
              CASE WHEN columns.max_length = -1 THEN '(max)'  
               ELSE '(' + CAST(columns.max_length/2 AS VARCHAR(4)) + ')'  
                        END 
          --types with a datetime precision 
         WHEN types.name IN ('time', 'datetime2', 'datetimeoffset') THEN types.name + 
                    '(' + CAST(columns.scale AS VARCHAR(4)) + ')' 

         --types with a precision/scale 
         WHEN types.name IN ('numeric', 'decimal') 
         THEN types.name + '(' + CAST(columns.precision AS VARCHAR(4)) + ',' + 
                    CAST(columns.scale AS VARCHAR(4)) + ')' 

         --timestamp should be reported as rowversion 
         WHEN types.name = 'timestamp' THEN 'rowversion' 
         --and the rest. Note, float is declared with a bit length, but is 
         --represented as either float or real in types 
         ELSE types.name 
        END AS declared_datatype, 

        --types that have a ascii character or binary length 
        CASE WHEN baseType.name IN ('varchar', 'char', 'varbinary') 
            THEN baseType.name + 
               CASE WHEN columns.max_length = -1 THEN '(max)' 
                ELSE '(' + CAST(columns.max_length AS VARCHAR(4)) + ')' 
               END 

         --types that have an unicode character type that requires length to be halved 
         WHEN baseType.name IN ('nvarchar', 'nchar') 
            THEN baseType.name + 
               CASE WHEN columns.max_length = -1 THEN '(max)'  
                ELSE '(' + CAST(columns.max_length/2 AS VARCHAR(4)) + ')'  
               END 

         --types with a datetime precision 
         WHEN baseType.name IN ('time', 'datetime2', 'datetimeoffset') 
            THEN baseType.name + '(' + CAST(columns.scale AS VARCHAR(4)) + ')' 

         --types with a precision/scale 
         WHEN baseType.name IN ('numeric', 'decimal') 
         THEN baseType.name + '(' + CAST(columns.precision AS VARCHAR(4)) + 
               ',' + CAST(columns.scale AS VARCHAR(4)) + ')' 

         --timestamp should be reported as rowversion 
         WHEN baseType.name = 'timestamp' THEN 'rowversion' 
         --and the rest. Note, float is declared with a bit length, but is 
         --represented as either float or real in types 
         ELSE baseType.name 
        END AS base_datatype, 
        CASE WHEN EXISTS (SELECT *  
             FROM sys.key_constraints  
               JOIN sys.indexes  
                 ON key_constraints.parent_object_id = indexes.object_id  
                  AND key_constraints.unique_index_id = indexes.index_id  
               JOIN sys.index_columns  
                 ON index_columns.object_id = indexes.object_id  
                  AND index_columns.index_id = indexes.index_id  
             WHERE key_constraints.type = 'PK'  
             AND columns.column_id = index_columns.column_id  
             AND columns.OBJECT_ID = index_columns.OBJECT_ID) 
            THEN 1  
          ELSE 0 END AS primary_key_column, 
        columns.column_id, default_constraints.definition AS default_value, 
        check_constraints.definition AS column_check_constraint, 
        CASE WHEN EXISTS (SELECT * 
             FROM  sys.check_constraints AS cc 
             WHERE cc.parent_object_id = columns.OBJECT_ID 
               AND cc.definition LIKE '%~[' + columns.name + '~]%' ESCAPE '~' 
               AND cc.parent_column_id = 0) THEN 1 
         ELSE 0 
        END AS table_check_constraint_reference 
      FROM  sys.columns 
        JOIN sys.types 
         ON columns.user_type_id = types.user_type_id 
        JOIN sys.types AS baseType 
         ON columns.system_type_id = baseType.system_type_id 
          AND baseType.user_type_id = baseType.system_type_id 
        JOIN sys.objects 
          JOIN sys.schemas 
            ON schemas.schema_id = objects.schema_id 
         ON objects.object_id = columns.OBJECT_ID 
        LEFT OUTER JOIN sys.default_constraints 
         ON default_constraints.parent_object_id = columns.object_id 
           AND default_constraints.parent_column_id = columns.column_id 
        LEFT OUTER JOIN sys.check_constraints 
         ON check_constraints.parent_object_id = columns.object_id 
          AND check_constraints.parent_column_id = columns.column_id) AS rows 
WHERE table_type = 'user table' 
       AND schema_name LIKE '%' 
       AND table_name LIKE '%' 
       AND column_name LIKE '%' 
       AND nullability LIKE '%' 
       AND base_datatype LIKE '%' 
       AND declared_datatype LIKE '%' 
ORDER BY table_type, schema_name, table_name, column_id 
+0

好極了,正是我需要的。 – Lunyx

+0

@Lunyx樂於助人! – SqlZim