15

Suppose I have a view in which some of the column names are aliases, like "surName" in this example:

CREATE VIEW myView AS
    SELECT  
            firstName,
            middleName,
            you.lastName surName
    FROM 
            myTable me
            LEFT OUTER JOIN yourTable you
            ON me.code = you.code
GO

I'm able to retrieve some information about the view using the INFORMATION_SCHEMA views.
For example, the query

SELECT column_name AS ALIAS, data_type AS TYPE
FROM information_schema.columns 
WHERE table_name = 'myView'

yields:

 ----------------
|ALIAS     |TYPE |
 ----------------
|firstName |nchar|
|middleName|nchar|
|surName   |nchar|
 ----------------

However, I would like to know the actual column name as well. Ideally:

 ---------------------------
|ALIAS     |TYPE |REALNAME  |
 ---------------------------
|firstName |nchar|firstName |
|middleName|nchar|middleName|
|surName   |nchar|lastName  |
 ---------------------------

How can I determine what the real column name is based on the alias? There must be some way to use the sys tables and/or INFORMATION_SCHEMA views to retrieve this information.


EDIT: I can get close with this abomination, which is similar to Arion's answer:

SELECT
    c.name AS ALIAS,
    ISNULL(type_name(c.system_type_id), t.name) AS DATA_TYPE,
    tablecols.name AS REALNAME
FROM 
    sys.views v
    JOIN sys.columns c ON c.object_id = v.object_id
    LEFT JOIN sys.types t ON c.user_type_id = t.user_type_id
    JOIN sys.sql_dependencies d ON d.object_id = v.object_id 
        AND c.column_id = d.referenced_minor_id
    JOIN sys.columns tablecols ON d.referenced_major_id = tablecols.object_id 
        AND tablecols.column_id = d.referenced_minor_id 
        AND tablecols.column_id = c.column_id
WHERE v.name ='myView'

This yields:

 ---------------------------
|ALIAS     |TYPE |REALNAME  |
 ---------------------------
|firstName |nchar|firstName |
|middleName|nchar|middleName|
|surName   |nchar|code      |
|surName   |nchar|lastName  |
 ---------------------------

but the third record is wrong -- this happens with any view created using a "JOIN" clause, because there are two columns with the same "column_id", but in different tables.

Justin Garrick
  • 14,767
  • 7
  • 41
  • 66
  • afaik, regular syntax for column alias is using `AS`: select columnA as columnB from t – abatishchev Apr 06 '12 at 19:13
  • 2
    The real name for a view may not even be a column, so there is no way of doing this. What would be the name of the column in this view ? Create view a as select 1 b – t-clausen.dk Apr 06 '12 at 22:30
  • So long as the [`VIEW_METADATA`](http://msdn.microsoft.com/en-us/library/ms187956.aspx) option is not set when creating the view SQL Server will return to the DB-Library, ODBC, and OLE DB APIs Browse-mode metadata including information about the base table that the columns in the result set belong to. Never looked at this aspect myself though. – Martin Smith Apr 09 '12 at 22:10
  • which version of SQL Server did you use? I'm trying to reproduce your query in SQL Server 2016 and it doesn't work – Roman Pekar Aug 12 '17 at 14:53

4 Answers4

11

Given this view:

CREATE VIEW viewTest
AS
SELECT
    books.id,
    books.author,
    Books.title AS Name
FROM
    Books

What I can see you can get the columns used and the tables used by doing this:

SELECT * 
FROM INFORMATION_SCHEMA.VIEW_COLUMN_USAGE AS UsedColumns 
WHERE UsedColumns.VIEW_NAME='viewTest'

SELECT * 
FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE AS UsedTables 
WHERE UsedTables.VIEW_NAME='viewTest'

This is for sql server 2005+. See reference here

Edit

Give the same view. Try this query:

SELECT
    c.name AS columnName,
    columnTypes.name as dataType,
    aliases.name as alias
FROM 
sys.views v 
JOIN sys.sql_dependencies d 
    ON d.object_id = v.object_id
JOIN .sys.objects t 
    ON t.object_id = d.referenced_major_id
JOIN sys.columns c 
    ON c.object_id = d.referenced_major_id 
JOIN sys.types AS columnTypes 
    ON c.user_type_id=columnTypes.user_type_id
    AND c.column_id = d.referenced_minor_id
JOIN sys.columns AS aliases
    on c.column_id=aliases.column_id
    AND aliases.object_id = object_id('viewTest')
WHERE
    v.name = 'viewTest';

It returns this for me:

columnName  dataType  alias

id          int       id
author      varchar   author
title       varchar   Name

This is also tested in sql 2005+

Arion
  • 31,011
  • 10
  • 70
  • 88
  • This is interesting, but there's nothing I can see in the INFORMATION_SCHEMA.VIEW_COLUMN_USAGE view that could be used in a join on in order to map to the alias name. In my example, the columns are returned in a different order. For INFORMATION_SCHEMA.COLUMNS, there's an "ORDINAL POSITION". No such luck for INFORMATION_SCHEMA.VIEW_COLUMN_USAGE. – Justin Garrick Apr 09 '12 at 12:52
  • Updated the answer.. Have look:P – Arion Apr 09 '12 at 15:39
  • 1
    Thanks, this is essentially what I can up with myself using sp_helptext to "reverse engineer" the INFORMATION_SCHEMA views, but your query suffers from the same problem as mine -- it will fail if the view is created from a JOIN. For example, it maps both the 'lastName' and 'code' fields to the 'surName' alias in my example. I will update the question to reflect this. – Justin Garrick Apr 09 '12 at 15:50
  • Can you try my query against your data? Because when I tried it, it looked like the result you are expecting. – Arion Apr 09 '12 at 21:32
  • Yes, I did. It has the same issue as my query with the "code" field used in the JOIN clause. – Justin Garrick Apr 10 '12 at 12:42
  • Could it be that VIEW_COLUMN_USAGE isn't very helpful here because if the view uses joins VIEW_COLUMN_USAGE also returns the columns used in the joins of the view even if they aren't reused during the SELECT I think. – user764754 Apr 25 '13 at 11:55
  • @justingarrick did you find a solution to your question? I've been trying to achieve the same result but I can't find a way to mix and match the different system views to actually map the aliased columns of a view to the respective columns of the real tables. – Valerio Santinelli Aug 01 '13 at 18:59
  • This query doesn't work in SQL Server 2016, cannot try in 2005. In 2016 there're no meaningful referenced_minor_id in sql_dependency view (except for those which used in foreign keys). – Roman Pekar Aug 12 '17 at 09:28
7

Having spent a number of hours trying to find an answer to this, and repeatedly running into solutions that didn't work and posters that appeared to eventually give up, I eventually stumbled across an answer here that appears to work:

https://social.msdn.microsoft.com/Forums/windowsserver/en-US/afa2ed2b-62de-4a5e-ae70-942e75f887a1/find-out-original-columns-name-when-used-in-a-view-with-alias?forum=transactsql

The following SQL returns, I believe, exactly what you're looking for, it's certainly doing what I need and appears to perform well too.

SELECT  name
    , source_database
    , source_schema
    , source_table
    , source_column
    , system_type_name
    , is_identity_column
FROM    sys.dm_exec_describe_first_result_set (N'SELECT * from ViewName', null, 1) 

Documentation on the sys.dm_exec_describe_first_result_set function can be found here, it's available in SQL Server 2012 and later:

https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-describe-first-result-set-transact-sql

Full credit to the poster on the link, I didn't work this out myself, but I wanted to post this here in case it's useful to anyone else searching for this information as I found this thread much more easily than the one I linked to.

Adam Dawes
  • 188
  • 2
  • 10
  • I tried to execute this SELECT name,source_column,* FROM sys.dm_exec_describe_first_result_set (N'SELECT 1 from Table ', null, 1) and result isnt correct – M.Vakili Aug 02 '21 at 06:07
  • Using `SELECT 1 FROM Table` in the SQL string doesn't work for me either, try changing it to select the actual columns you want, or use `SELECT * FROM Table`. That has worked fine for me in hundreds of instances (I've built a debugger into my application that works on the basis of this approach). – Adam Dawes Aug 03 '21 at 07:07
  • Tank you for replay .. but I think the problem is much more ... please look at https://stackoverflow.com/questions/68624758/detect-sql-view-structure @adam-dawes – M.Vakili Aug 03 '21 at 08:29
5

I think you can't.

Select query hides actual data source it was performed against. Because you can query anything, i.e. view, table, even linked remote server.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • @Segphault: Why do you downvote my answer without a comment? Don't you agree? Okay. But that's not a reason for downvote, imo. – abatishchev Apr 06 '12 at 19:20
  • Makes sense. One use of a View is to hide the details from prying eyes. Have to expose the type for it to be consumed. +1 – paparazzo Apr 06 '12 at 19:47
2

Not a Perfect solution; but, it is possible to parse the view_definition with a high degree of accuracy especially if the code is well organized with consistent aliasing by 'as'. Additionally, one can parse for a comma ',' after the alias.

Of note: the final field in the select clause will not have the comma and I was unable to exclude items being used as comments (for example interlaced in the view text with --)

I wrote the below for a table named 'My_Table' and view correspondingly called 'vMy_Table'

select alias, t.COLUMN_name
from 
(
select VC.COLUMN_NAME, 



case when
ROW_NUMBER () OVER (
partition by C.COLUMN_NAME order by 
CHARINDEX(',',VIEW_DEFINITION,CHARINDEX(C.COLUMN_NAME,VIEW_DEFINITION))- 
CHARINDEX(VC.COLUMN_NAME,VIEW_DEFINITION)

) = 1

then 1
else 0 end
as lenDiff



,C.COLUMN_NAME as alias

 ,CHARINDEX(',',VIEW_DEFINITION,CHARINDEX(C.COLUMN_NAME,VIEW_DEFINITION)) diff1
 , CHARINDEX(VC.COLUMN_NAME,VIEW_DEFINITION) diff2

 from INFORMATION_SCHEMA.VIEW_COLUMN_USAGE VC
inner join INFORMATION_SCHEMA.VIEWS V on V.TABLE_NAME = 'v'+VC.TABLE_Name
inner join information_schema.COLUMNS C on C.TABLE_NAME = 'v'+VC.TABLE_Name
where VC.TABLE_NAME = 'My_Table'
and CHARINDEX(',',VIEW_DEFINITION,CHARINDEX(C.COLUMN_NAME,VIEW_DEFINITION))- 
CHARINDEX(VC.COLUMN_NAME,VIEW_DEFINITION) >0
)
t

where lenDiff = 1 

Hope this helps and I look forward to your feedback

  • 1
    If you're going to parse the actual SQL, you might want to just script out the definitions to a file and use a language that makes life easier for you, e.g. Python. – 10762409 Oct 24 '19 at 17:38