Question

I've a SQL query that queries an enormous (as in, hundreds of views/tables with hard-to-read names like CMM-CPP-FAP-ADD) database that I don't need nor want to understand. The result of this query needs to be stored in a staging table to feed a report.

I need to create the staging table, but with hundreds of views/tables to dig through to find the data types that are being represented here, I have to wonder if there's a better way to construct this table.

Can anyone advise how I would use any of the SQL Server 2008 tools to divine the source data types in my SQL 2000 database?

As a general example, I want to know from a query like:

SELECT Auth_First_Name, Auth_Last_Name, Auth_Favorite_Number 
FROM Authors

Instead of the actual results, I want to know that:

Auth_First_Name is char(25)
Auth_Last_Name is char(50)
Auth_Favorite_Number is int

I'm not interested in constraints, I really just want to know the data types.

Was it helpful?

Solution

select * from information_schema.columns

could get you started.

OTHER TIPS

You could also insert the results (or top 10 results) into a temp table and get the columns from the temp table (as long as the column names are all different).

SELECT TOP 10 *
INTO #TempTable
FROM <DataSource>

Then use:

EXEC tempdb.dbo.sp_help N'#TempTable';

or

SELECT * 
FROM tempdb.sys.columns 
WHERE [object_id] = OBJECT_ID(N'tempdb..#TempTable');

Extrapolated from Aaron's answer here.

You can also use...

SQL_VARIANT_PROPERTY()

...in cases where you don't have direct access to the metadata (e.g. a linked server query perhaps?).

http://msdn.microsoft.com/en-us/library/ms178550.aspx

In SQL Server 2005 and beyond you are better off using the catalog views (sys.columns) as opposed to INFORMATION_SCHEMA. Unless portability to other platforms is important. Just keep in mind that the INFORMATION_SCHEMA views won't change and so they will progressively be lacking information on new features etc. in successive versions of SQL Server.

There MUST be en easier way to do this... Low and behold, there is...!

"sp_describe_first_result_set" is your friend!

Now I do realise the question was asked specifically for SQL Server 2000, but I was looking for a similar solution for later versions and discovered some native support in SQL to achieve this.

In SQL Server 2012 onwards cf. "sp_describe_first_result_set" - Link to BOL

I had already implemented a solution using a technique similar to @Trisped's above and ripped it out to implement the native SQL Server implementation.

In case you're not on SQL Server 2012 or Azure SQL Database yet, here's the stored proc I created for pre-2012 era databases:

CREATE PROCEDURE [fn].[GetQueryResultMetadata] 
    @queryText VARCHAR(MAX)
AS
BEGIN

    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    --SET NOCOUNT ON;

    PRINT @queryText;

    DECLARE
                @sqlToExec NVARCHAR(MAX) = 
                    'SELECT TOP 1 * INTO #QueryMetadata FROM ('
                    +
                    @queryText
                    +
                    ') T;'
                    + '
                        SELECT
                                    C.Name                          [ColumnName],
                                    TP.Name                         [ColumnType],
                                    C.max_length                    [MaxLength],
                                    C.[precision]                   [Precision],
                                    C.[scale]                       [Scale],
                                    C.[is_nullable]                 IsNullable
                        FROM
                                    tempdb.sys.columns              C
                                        INNER JOIN
                                    tempdb.sys.types                TP
                                                                                ON
                                                                                        TP.system_type_id = C.system_type_id
                                                                                            AND
                                                                                        -- exclude custom types
                                                                                        TP.system_type_id = TP.user_type_id
                        WHERE
                                    [object_id] = OBJECT_ID(N''tempdb..#QueryMetadata'');
            '

    EXEC sp_executesql @sqlToExec

END

For SQL Server 2012 and above: If you place the query into a string then you can get the result set data types like so:

DECLARE @query nvarchar(max) = 'select 12.1 / 10.1 AS [Column1]';
EXEC sp_describe_first_result_set @query, null, 0;  
SELECT COLUMN_NAME,
       DATA_TYPE,
       CHARACTER_MAXIMUM_LENGTH
FROM information_schema.columns
WHERE TABLE_NAME = 'YOUR_TABLE_NAME'

You can use columns aliases for better looking output.

Can you get away with recreating the staging table from scratch every time the query is executed? If so you could use SELECT ... INTO syntax and let SQL Server worry about creating the table using the correct column types etc.

SELECT *
INTO your_staging_table
FROM enormous_collection_of_views_tables_etc
select COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH 
from INFORMATION_SCHEMA.COLUMNS 
where TABLE_NAME='yourTable';

This will give you everything column property related.

SELECT * INTO TMP1
FROM ( SELECT TOP 1 /* rest of your query expression here */ );

SELECT o.name AS obj_name, TYPE_NAME(c.user_type_id) AS type_name, c.*  
FROM sys.objects AS o   
JOIN sys.columns AS c  ON o.object_id = c.object_id  
WHERE o.name = 'TMP1';

DROP TABLE TMP1;

sp_describe_first_result_set

will help to identify the datatypes of query by analyzing datatypes of first resultset of query

https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-describe-first-result-set-transact-sql?view=sql-server-2017

I use a simple case statement to render results I can use in technical specification documents. This example does not contain every condition you will run into with a database, but it gives you a good template to work with.

SELECT
     TABLE_NAME          AS 'Table Name',
     COLUMN_NAME         AS 'Column Name',
     CASE WHEN DATA_TYPE LIKE '%char'
          THEN DATA_TYPE + '(' + CONVERT(VARCHAR, CHARACTER_MAXIMUM_LENGTH) + ')'
          WHEN DATA_TYPE IN ('bit', 'int', 'smallint', 'date')
          THEN DATA_TYPE
          WHEN DATA_TYPE = 'datetime'
          THEN DATA_TYPE + '(' + CONVERT(VARCHAR, DATETIME_PRECISION) + ')'
          WHEN DATA_TYPE = 'float'
          THEN DATA_TYPE
          WHEN DATA_TYPE IN ('numeric', 'money')
          THEN DATA_TYPE + '(' + CONVERT(VARCHAR, NUMERIC_PRECISION) + ', ' + CONVERT(VARCHAR, NUMERIC_PRECISION_RADIX) + ')'
     END                 AS 'Data Type',
     CASE WHEN IS_NULLABLE = 'NO'
          THEN 'NOT NULL'
          ELSE 'NULL'
     END                 AS 'PK/LK/NOT NULL'
FROM INFORMATION_SCHEMA.COLUMNS 
ORDER BY 
     TABLE_NAME, ORDINAL_POSITION
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top